home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / os2 / memsz313.zip / SOURCE.ZIP / MEMSIZE.CPP < prev    next >
C/C++ Source or Header  |  1996-04-02  |  142KB  |  3,262 lines

  1. /**************************************************************** MEMSIZE.CPP
  2.  *                                                                          *
  3.  * System Resources Monitor                                                 *
  4.  *                                                                          *
  5.  * (C) Copyright 1991-1995 by Richard W. Papo.                              *
  6.  *                                                                          *
  7.  * This is 'FreeWare'.  As such, it may be copied and distributed           *
  8.  * freely.  If you want to use part of it in your own program, please       *
  9.  * give credit where credit is due.  If you want to change the              *
  10.  * program, please refer the change request to me or send me the            *
  11.  * modified source code.  I can be reached at CompuServe 72607,3111         *
  12.  * and on Internet at RPapo@Msen.com.                                       *
  13.  *                                                                          *
  14.  ****************************************************************************/
  15.  
  16. // Bugs to Fix:
  17. //
  18. //   (1) When Float To Top is active, then the E editor dies upon displaying
  19. //       its file-type-set dialog.  CLOCK has the same problem.  IBM's bug, which
  20. //       was fixed with the Warp FixPak 17.
  21. //
  22. //   (2) Fix one bug, cause another (it seems).  When the Warp FixPak 17 has been 
  23. //       installed, then the window will not bring itself to the top of the Z-order 
  24. //       with a simple mouse click in the usual way.  Once the Context Menu has 
  25. //       been summoned (even once) the window behaves normally again.  I have been 
  26. //       unable to determine the cause of this.
  27. //
  28. //   (3) Drive space overflow when individual drives exceed 4GB in size.
  29. //
  30. //
  31. // Things to do:
  32. //
  33. //   (1) Add option for configuring the time/date field's justification (left/center/right).
  34. //
  35. //   (2) Add menu option to reset drives, and do so automatically once in a while.
  36. //
  37. //   (3) Revise ResetDefaults to reset -all- defaults, including monitor priority, anchor, etc.
  38. //
  39. //   (4) Add option for year in date.
  40. //
  41. //   (5) Add displayable item for Average CPU Load.  Add menu item to reset it.
  42. //
  43. //   (6) Bring the date-format support from Escriba over here.
  44. //
  45. //
  46.  
  47. #define INCL_BASE
  48. #define INCL_PM
  49. #include <os2.h>
  50.  
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include <time.h>
  55.  
  56. #include "Dde.h"
  57. #include "Debug.h"
  58. #include "DQPS.h"
  59. #include "Event.h"
  60. #include "Except.h"
  61. #include "HelpWin.h"
  62. #include "Module.h"
  63. #include "Process.h"
  64. #include "Profile.h"
  65. #include "ReString.h"
  66. #include "Support.h"
  67. #include "Thread.h"
  68. #include "Window.h"
  69.  
  70. #include "About.h"
  71. #include "Config.h"
  72.  
  73. #include "Items.h"
  74.  
  75. #include "MemSize.h"
  76.  
  77. #define STATIC
  78.  
  79.  
  80. /****************************************************************************
  81.  *                                                                          *
  82.  *                       Definitions & Declarations                         *
  83.  *                                                                          *
  84.  ****************************************************************************/
  85.  
  86.   // Constants
  87.  
  88. #define WM_REFRESH        (WM_USER)
  89.  
  90.  
  91.   // Data Types
  92.  
  93. typedef struct {
  94.    BOOL Active ;
  95.    PULONG Counter ;
  96.    PUSHORT Interval ;
  97.    PBYTE Priority ;
  98.    HWND Owner ;
  99. } MONITOR_PARMS, *PMONITOR_PARMS ;
  100.  
  101. typedef struct {
  102.    BOOL Active ;
  103.    ULONG Counter ;
  104. } COUNTER_PARMS, *PCOUNTER_PARMS ;
  105.  
  106. typedef struct {      // Data structure for window.
  107.    Process       *Proc ;
  108.    Module        *Library ;
  109.    Profile       *IniFile ;
  110.  
  111.    INIDATA        IniData ;
  112.  
  113.    TID            CounterTID ;
  114.    COUNTER_PARMS  CounterParms ;
  115.  
  116.    TID            MonitorTID ;
  117.    MONITOR_PARMS  MonitorParms ;
  118.  
  119.    HWND           TitleBar ;
  120.    HWND           SysMenu ;
  121.    HWND           MinMax ;
  122.    HWND           Menu ;
  123.  
  124.    ULONG          Drives ;
  125.  
  126.    long           Width ;
  127.    long           Height ;
  128.    int            MaxColumns ;
  129.  
  130.    FONTMETRICS    FontMetrics ;
  131.    LONG           CharMode ;
  132.    SIZEF          CharBox ;
  133.    USHORT         CodePage ;
  134.  
  135.    Dde_Server    *pDdeServer ;
  136.  
  137. } DATA, *PDATA ;
  138.  
  139. typedef struct {
  140.    short Filler ;
  141.    Process *Proc ;
  142.    Module *Library ;
  143.    Profile *IniFile ;
  144.    USHORT CodePage ;
  145. } PARMS, *PPARMS ;
  146.  
  147.  
  148.   // Function Prototypes
  149.  
  150. extern int main ( int argc, char *argv[] ) ;
  151.  
  152. STATIC FNWP MessageProcessor ;
  153.  
  154. STATIC FNWP Create ;
  155. STATIC FNWP Destroy ;
  156. STATIC FNWP Size ;
  157. STATIC FNWP SaveApplication ;
  158. STATIC FNWP Paint ;
  159. static FNWP InitMenu ;
  160. STATIC FNWP Command ;
  161. STATIC FNWP ResetDefaults ;
  162. STATIC FNWP HideControlsCmd ;
  163. STATIC FNWP Configure ;
  164. STATIC FNWP ResetLoad ;
  165. STATIC FNWP Copy ;
  166. STATIC FNWP About ;
  167. STATIC FNWP BeginDrag ;
  168. STATIC FNWP ButtonDblClick ;
  169. STATIC FNWP ContextMenu ;
  170. STATIC FNWP PresParamChanged ;
  171. STATIC FNWP SysColorChange ;
  172. STATIC FNWP QueryKeysHelp ;
  173. STATIC FNWP HelpError ;
  174. STATIC FNWP ExtHelpUndefined ;
  175. STATIC FNWP HelpSubitemNotFound ;
  176. STATIC FNWP Refresh ;
  177. STATIC FNWP Dde_Initiate ;
  178.  
  179. STATIC int GetIniData ( HAB Anchor, HMODULE Library, HINI IniHandle, PINIDATA IniData, Dde_Server *pDdeServer ) ;
  180. STATIC PSZ ScanSystemConfig ( HAB Anchor, PSZ Keyword ) ;
  181. STATIC char *CopyString ( char *Buffer, char *Original ) ;
  182.  
  183. STATIC void ResizeWindow ( HWND hwnd ) ;
  184.  
  185. STATIC void HideControls ( BOOL fHide, HWND Frame,
  186.    HWND SysMenu, HWND TitleBar, HWND MinMax ) ;
  187.  
  188. STATIC void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All ) ;
  189.  
  190. STATIC VOID MonitorLoopThread ( PVOID Parameter ) ;
  191.  
  192. STATIC VOID UpdateDriveList (
  193.    HAB Anchor, HMODULE Library, HINI IniHandle, PINIDATA IniData,
  194.    Dde_Server *pDdeServer, ULONG OldDrives, ULONG NewDrives ) ;
  195.  
  196. STATIC int CheckDrive ( USHORT Drive, PBYTE FileSystem, PBYTE DiskLabel ) ;
  197.  
  198. STATIC ULONG CalibrateLoadMeter ( PCOUNTER_PARMS Parms ) ;
  199.  
  200. STATIC VOID CounterThread ( PVOID Parameter ) ;
  201.  
  202.  
  203.   // Global Data
  204.  
  205. static Process Proc ;                           // Must be declared first.
  206. static Module Library ( PSZ(PROGRAM_NAME) ) ;
  207.  
  208. static Event CounterThreadEvent = Event ( ) ;
  209. static Event MonitorThreadEvent = Event ( ) ;
  210.  
  211. HMODULE LibraryHandle ;
  212.  
  213.  
  214. /****************************************************************************
  215.  *                                                                          *
  216.  *      Program Mainline                                                    *
  217.  *                                                                          *
  218.  ****************************************************************************/
  219.  
  220. extern int main ( int argc, char *argv[] ) {
  221.  
  222.   /**************************************************************************
  223.    * Save the resource library handle for the exception handler to use.     *
  224.    **************************************************************************/
  225.  
  226.    LibraryHandle = Library.QueryHandle() ;
  227.  
  228.   /**************************************************************************
  229.    * Get the program title.                                                 *
  230.    **************************************************************************/
  231.  
  232.    ResourceString Title ( Library.QueryHandle(), IDS_TITLE ) ;
  233.  
  234.   /**************************************************************************
  235.    * Set the codepage.  Abort if unable to do so.                           *
  236.    **************************************************************************/
  237.  
  238.    PVOID Offset ;
  239.    DosGetResource ( Library.QueryHandle(), RT_RCDATA, 1, &Offset ) ;
  240.  
  241.    PUSHORT pCodePage = PUSHORT ( Offset ) ;
  242.    USHORT DisplayCodePage = *pCodePage ;
  243.  
  244.    static PSZ pszData [2] = { 0, PSZ("Display") } ;
  245.    HDC MemoryDC = DevOpenDC ( Proc.QueryAnchor(), OD_MEMORY, PSZ("*"), 2, PDEVOPENDATA(pszData), 0 ) ;
  246.    SIZEL PageSize = { 0, 0 } ;
  247.    HPS hPS = GpiCreatePS ( Proc.QueryAnchor(), MemoryDC, &PageSize, PU_PELS | GPIA_ASSOC | GPIT_MICRO ) ;
  248.    while ( *pCodePage ) {
  249.       if ( GpiSetCp ( hPS, *pCodePage ) )
  250.          DisplayCodePage = *pCodePage ;
  251.       if ( !DosSetProcessCp ( *pCodePage ) )
  252.          if ( WinSetCp ( Proc.QueryQueue(), *pCodePage ) )
  253.             break ;
  254.       pCodePage ++ ;
  255.    } /* endwhile */
  256.    GpiDestroyPS ( hPS ) ;
  257.    DevCloseDC ( MemoryDC ) ;
  258.  
  259.    if ( *pCodePage == 0 ) {
  260.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_BADCODEPAGE ) ;
  261.       CHAR Message [200] ;
  262.       sprintf ( Message, PCHAR(Format), *pCodePage ) ;
  263.       Log ( "%s", Message ) ;
  264.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  265.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  266.       return ( 1 ) ;
  267.    } /* endif */
  268.  
  269.   /**************************************************************************
  270.    * Decipher command-line parameters.                                      *
  271.    **************************************************************************/
  272.  
  273.    BOOL Reset = FALSE ;
  274.  
  275.    ResourceString ResetCommand ( Library.QueryHandle(), IDS_PARMS_RESET ) ;
  276.  
  277.    while ( --argc ) {
  278.  
  279.       argv ++ ;
  280.  
  281.       if ( *argv[0] == '?' ) {
  282.          ResourceString Message ( Library.QueryHandle(), IDS_PARAMETERLIST ) ;
  283.          WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  284.             PSZ(Title), 0, MB_ENTER | MB_NOICON ) ;
  285.          return ( 0 ) ;
  286.       } /* endif */
  287.  
  288.       if ( !stricmp ( *argv, PCHAR(ResetCommand) ) ) {
  289.          Reset = TRUE ;
  290.          continue ;
  291.       } /* endif */
  292.  
  293.       #if 0
  294.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_INVALIDPARM ) ;
  295.       BYTE Message [200] ;
  296.       sprintf ( PCHAR(Message), PCHAR(Format), *argv ) ;
  297.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  298.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  299.       return ( 1 ) ;
  300.       #endif
  301.  
  302.    } /* endwhile */
  303.  
  304.   /**************************************************************************
  305.    * Create the help instance.                                              *
  306.    **************************************************************************/
  307.  
  308.    ResourceString HelpTitle ( Library.QueryHandle(), IDS_HELPTITLE ) ;
  309.  
  310.    HelpWindow Help ( Proc.QueryAnchor(), 0,
  311.       ID_MAIN, PSZ(PROGRAM_NAME ".hlp"), PSZ(HelpTitle) ) ;
  312.  
  313.    if ( Help.QueryHandle() == 0 ) {
  314.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  315.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATEHELP ) ;
  316.       CHAR Message [200] ;
  317.       sprintf ( Message, PCHAR(Format), Error ) ;
  318.       Log ( "%s", Message ) ;
  319.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  320.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  321.    } /* endif */
  322.  
  323.   /**************************************************************************
  324.    * Open/create the profile file.  Reset if requested.                     *
  325.    **************************************************************************/
  326.  
  327.    Profile IniFile ( PSZ(PROGRAM_NAME),
  328.       Proc.QueryAnchor(), Library.QueryHandle(),
  329.       IDD_PROFILE_PATH, Help.QueryHandle(), Reset ) ;
  330.  
  331.    if ( IniFile.QueryHandle() == 0 ) {
  332.       ResourceString Message ( Library.QueryHandle(), IDS_ERROR_PRFOPENPROFILE ) ;
  333.       Log ( "%s", PSZ(Message) ) ;
  334.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  335.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  336.       return ( 2 ) ;
  337.    } /* endif */
  338.  
  339.   /**************************************************************************
  340.    * Read the profile to find out if we're to animate the frame window.     *
  341.    **************************************************************************/
  342.  
  343.    INIDATA IniData ;
  344.    if ( GetIniData ( HINI_USERPROFILE, &IniData ) ) {
  345.       GetIniData ( IniFile.QueryHandle(), &IniData ) ;
  346.    } else {
  347.       PutIniData ( IniFile.QueryHandle(), &IniData ) ;
  348.       PrfWriteProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), 0, 0, 0 ) ;
  349.    } /* endif */
  350.  
  351.   /**************************************************************************
  352.    * Create the frame window.                                               *
  353.    **************************************************************************/
  354.  
  355.    FRAMECDATA FrameControlData ;
  356.    FrameControlData.cb = sizeof(FrameControlData) ;
  357.    FrameControlData.flCreateFlags =
  358.       FCF_TITLEBAR | FCF_SYSMENU | FCF_BORDER |
  359.       FCF_ICON | FCF_MINBUTTON | FCF_NOBYTEALIGN | FCF_ACCELTABLE ;
  360.    FrameControlData.hmodResources = 0 ;
  361.    FrameControlData.idResources = ID_MAIN ;
  362.  
  363.    Window Frame ( HWND_DESKTOP, WC_FRAME, PSZ(Title),
  364.       IniData.fAnimate AND IniData.Animate ? WS_ANIMATE : 0,
  365.       0, 0, 0, 0, HWND_DESKTOP, HWND_TOP, ID_MAIN,
  366.       &FrameControlData, NULL ) ;
  367.  
  368.    if ( Frame.QueryHandle() == 0 ) {
  369.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  370.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATEFRAME ) ;
  371.       CHAR Message [200] ;
  372.       sprintf ( Message, PCHAR(Format), Error ) ;
  373.       Log ( "%s", Message ) ;
  374.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  375.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  376.       return ( 3 ) ;
  377.    } /* endif */
  378.  
  379.   /**************************************************************************
  380.    * Associate the help instance with the frame window.                     *
  381.    **************************************************************************/
  382.  
  383.    if ( Help.QueryHandle() )
  384.       WinAssociateHelpInstance ( Help.QueryHandle(), Frame.QueryHandle() ) ;
  385.  
  386.   /**************************************************************************
  387.    * Register the client window class.                                      *
  388.    **************************************************************************/
  389.  
  390.    if ( !WinRegisterClass ( Proc.QueryAnchor(), PSZ(CLASS_NAME),
  391.       MessageProcessor, CS_MOVENOTIFY, sizeof(PVOID) ) ) {
  392.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  393.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_WINREGISTERCLASS ) ;
  394.       CHAR Message [200] ;
  395.       sprintf ( Message, PCHAR(Format), CLASS_NAME, Error ) ;
  396.       Log ( "%s", Message ) ;
  397.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  398.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  399.       return ( 4 ) ;
  400.    } /* endif */
  401.  
  402.   /**************************************************************************
  403.    * Build the presentation parameters for the client window.               *
  404.    **************************************************************************/
  405.  
  406.    USHORT ParmCount = 0 ;
  407.    ULONG Ids [3] ;
  408.    ULONG ByteCounts [3] ;
  409.    PBYTE Params [3] ;
  410.  
  411.    if ( IniData.fTextColor ) {
  412.       Ids [ParmCount] = PP_FOREGROUNDCOLOR ;
  413.       ByteCounts [ParmCount] = sizeof(IniData.TextColor) ;
  414.       Params [ParmCount++] = PBYTE ( &IniData.TextColor ) ;
  415.    } /* endif */
  416.  
  417.    if ( IniData.fBackColor ) {
  418.       Ids [ParmCount] = PP_BACKGROUNDCOLOR ;
  419.       ByteCounts [ParmCount] = sizeof(IniData.BackColor) ;
  420.       Params [ParmCount++] = PBYTE ( &IniData.BackColor ) ;
  421.    } /* endif */
  422.  
  423.    if ( IniData.fFontNameSize ) {
  424.       Ids [ParmCount] = PP_FONTNAMESIZE ;
  425.       ByteCounts [ParmCount] = strlen(PCHAR(IniData.FontNameSize)) + 1 ;
  426.       Params [ParmCount++] = PBYTE ( IniData.FontNameSize ) ;
  427.    } /* endif */
  428.  
  429.    PPRESPARAMS PresParams = BuildPresParams ( ParmCount, Ids, ByteCounts, Params ) ;
  430.  
  431.   /**************************************************************************
  432.    * Create the client window.                                              *
  433.    **************************************************************************/
  434.  
  435.    PARMS Parms ;
  436.    Parms.Filler = 0 ;
  437.    Parms.Proc = & Proc ;
  438.    Parms.Library = & Library ;
  439.    Parms.IniFile = & IniFile ;
  440.    Parms.CodePage = DisplayCodePage ;
  441.  
  442.    Window Client ( Frame.QueryHandle(), PSZ(CLASS_NAME), PSZ(""), 0, 0, 0, 0, 0,
  443.       Frame.QueryHandle(), HWND_BOTTOM, FID_CLIENT, &Parms, PresParams ) ;
  444.  
  445.    if ( Client.QueryHandle() == 0 ) {
  446.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  447.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATECLIENT ) ;
  448.       CHAR Message [200] ;
  449.       sprintf ( Message, PCHAR(Format), Error ) ;
  450.       Log ( "%s", Message ) ;
  451.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  452.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  453.       return ( 5 ) ;
  454.    } /* endif */
  455.  
  456.   /**************************************************************************
  457.    * Wait for and process messages to the window's queue.  Terminate        *
  458.    *   when the WM_QUIT message is received.                                *
  459.    **************************************************************************/
  460.  
  461.    QMSG QueueMessage ;
  462.    while ( WinGetMsg ( Proc.QueryAnchor(), &QueueMessage, 0, 0, 0 ) ) {
  463.       WinDispatchMsg ( Proc.QueryAnchor(), &QueueMessage ) ;
  464.    } /* endwhile */
  465.  
  466.   /**************************************************************************
  467.    * Discard all that was requested of the system and terminate.            *
  468.    **************************************************************************/
  469.  
  470.    return ( 0 ) ;
  471. }
  472.  
  473. /****************************************************************************
  474.  *                                                                          *
  475.  *      Window Message Processor                                            *
  476.  *                                                                          *
  477.  ****************************************************************************/
  478.  
  479. STATIC MRESULT EXPENTRY MessageProcessor ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  480.  
  481.   /**************************************************************************
  482.    * Dispatch the message according to the method table and return the      *
  483.    *   result.  Any messages not defined above get handled by the system    *
  484.    *   default window processor.                                            *
  485.    **************************************************************************/
  486.  
  487.    static METHOD Methods [] = {
  488.       { WM_CREATE,                Create              },
  489.       { WM_DESTROY,               Destroy             },
  490.       { WM_SIZE,                  Size                },
  491.       { WM_MOVE,                  Size                },
  492.       { WM_SAVEAPPLICATION,       SaveApplication     },
  493.       { WM_PAINT,                 Paint               },
  494.       { WM_INITMENU,              InitMenu            },
  495.       { WM_COMMAND,               Command             },
  496.       { WM_BEGINSELECT,           BeginDrag           },
  497.       { WM_BEGINDRAG,             BeginDrag           },
  498.       { WM_BUTTON1DBLCLK,         ButtonDblClick      },
  499.       { WM_CONTEXTMENU,           ContextMenu         },
  500.       { WM_PRESPARAMCHANGED,      PresParamChanged    },
  501.       { WM_SYSCOLORCHANGE,        SysColorChange      },
  502.       { HM_QUERY_KEYS_HELP,       QueryKeysHelp       },
  503.       { HM_ERROR,                 HelpError           },
  504.       { HM_EXT_HELP_UNDEFINED,    ExtHelpUndefined    },
  505.       { HM_HELPSUBITEM_NOT_FOUND, HelpSubitemNotFound },
  506.       { WM_REFRESH,               Refresh             },
  507.       { WM_DDE_INITIATE,          Dde_Initiate        },
  508.    } ;
  509.  
  510.    #ifdef DEBUG
  511.    static int Indent = 0 ;
  512.    Log ( "%*sMAIN: Message %08X received.  Parm1=%08X, Parm2=%08X.", Indent, "", msg, mp1, mp2 ) ;
  513.    Indent += 2 ;
  514.    #endif
  515.  
  516.    MRESULT Result = DispatchMessage ( hwnd, msg, mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), WinDefWindowProc ) ;
  517.  
  518.    #ifdef DEBUG
  519.    Indent -= 2 ;
  520.    Log ( "%*sMAIN: Message %08X done.  Result %08X.", Indent, "", msg, Result ) ;
  521.    #endif
  522.  
  523.    return ( Result ) ;
  524. }
  525.  
  526. /****************************************************************************
  527.  *                                                                          *
  528.  *      Create the main window.                                             *
  529.  *                                                                          *
  530.  ****************************************************************************/
  531.  
  532. STATIC MRESULT APIENTRY Create ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  533.  
  534.  /***************************************************************************
  535.   * Allocate instance data.                                                 *
  536.   ***************************************************************************/
  537.  
  538.   PDATA Data = PDATA ( malloc ( sizeof(DATA) ) ) ;
  539.  
  540.   memset ( Data, 0, sizeof(DATA) ) ;
  541.  
  542.   WinSetWindowPtr ( hwnd, QWL_USER, Data ) ;
  543.  
  544.  /***************************************************************************
  545.   * Grab any parameters from the WM_CREATE message.                         *
  546.   ***************************************************************************/
  547.  
  548.   PPARMS Parms = PPARMS ( PVOIDFROMMP ( mp1 ) ) ;
  549.  
  550.   Data->Proc = Parms->Proc ;
  551.   Data->Library = Parms->Library ;
  552.   Data->IniFile = Parms->IniFile ;
  553.   Data->CodePage = Parms->CodePage ;
  554.  
  555.  /***************************************************************************
  556.   * Initialize the DDE Server.                                              *
  557.   ***************************************************************************/
  558.  
  559.   Data->pDdeServer = new Dde_Server ( Data->Proc->QueryAnchor(),
  560.      Data->Library->QueryHandle(), hwnd, PROGRAM_NAME ) ;
  561.  
  562.   Data->pDdeServer->AddTopic ( SZDDESYS_TOPIC, SZDDESYS_ITEM_SYSITEMS ) ;
  563.  
  564.   char *Topics = SZDDESYS_TOPIC "\t" "Items" ;
  565.   Data->pDdeServer->AddItem ( SZDDESYS_TOPIC, SZDDESYS_ITEM_TOPICS, DDEFMT_TEXT, Topics, strlen(Topics)+1 ) ;
  566.  
  567.   char *Protocols = "" ;
  568.   Data->pDdeServer->AddItem ( SZDDESYS_TOPIC, SZDDESYS_ITEM_PROTOCOLS, DDEFMT_TEXT, Protocols, strlen(Protocols)+1 ) ;
  569.  
  570.   Data->pDdeServer->AddTopic ( "Items", "Items" ) ;
  571.  
  572.  /***************************************************************************
  573.   * Load the window context menu.                                           *
  574.   ***************************************************************************/
  575.  
  576.   Data->Menu = WinLoadMenu ( HWND_DESKTOP, Data->Library->QueryHandle(), IDM_MENU ) ;
  577.   if ( Data->Menu == 0 ) {
  578.      ERRORID Error = WinGetLastError ( Data->Proc->QueryAnchor() ) ;
  579.      Log ( "WARNING: Unable to create context menu.  Error %08lX.", Error ) ;
  580.   } /* endif */
  581.  
  582.  /***************************************************************************
  583.   * Get the current drive mask.                                             *
  584.   ***************************************************************************/
  585.  
  586.   ULONG Drive ;
  587.   DosQueryCurrentDisk ( &Drive, &Data->Drives ) ;
  588.  
  589.  /***************************************************************************
  590.   * Calibrate the old-style load meter, if the high resolution timer's      *
  591.   *   available.                                                            *
  592.   ***************************************************************************/
  593.  
  594.   Data->IniData.MaxCount = CalibrateLoadMeter ( &Data->CounterParms ) ;
  595.   Data->IniData.MaxCount = (ULONG) max ( 1, Data->IniData.MaxCount ) ;
  596.  
  597.  /***************************************************************************
  598.   * Get profile data. Try the OS2.INI first, then try for private INI.      *
  599.   *   If obtained from OS2.INI, erase it afterwards.                        *
  600.   ***************************************************************************/
  601.  
  602.   if ( GetIniData ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), HINI_USERPROFILE, &Data->IniData, Data->pDdeServer ) ) {
  603.      GetIniData ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), Data->IniFile->QueryHandle(), &Data->IniData, Data->pDdeServer ) ;
  604.   } else {
  605.      PutIniData ( Data->IniFile->QueryHandle(), &Data->IniData ) ;
  606.      PrfWriteProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), 0, 0, 0 ) ;
  607.   } /* endif */
  608.  
  609.  /***************************************************************************
  610.   * Get the frame handle.                                                   *
  611.   ***************************************************************************/
  612.  
  613.   HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  614.  
  615.  /***************************************************************************
  616.   * Get the control window handles.                                         *
  617.   ***************************************************************************/
  618.  
  619.   Data->SysMenu  = WinWindowFromID ( Frame, FID_SYSMENU  ) ;
  620.   Data->TitleBar = WinWindowFromID ( Frame, FID_TITLEBAR ) ;
  621.   Data->MinMax   = WinWindowFromID ( Frame, FID_MINMAX   ) ;
  622.  
  623.  /***************************************************************************
  624.   * Add basic extensions to the system menu.                                *
  625.   ***************************************************************************/
  626.  
  627.   static MENUITEM MenuSeparator =
  628.      { MIT_END, MIS_SEPARATOR, 0, 0, 0, 0 } ;
  629.  
  630.   AddSysMenuItem ( Frame, &MenuSeparator, 0 ) ;
  631.  
  632.   static MENUITEM MenuItems [] = {
  633.      { MIT_END, MIS_TEXT,      0, IDM_SAVE_APPLICATION, 0, 0 },
  634.      { MIT_END, MIS_TEXT,      0, IDM_RESET_DEFAULTS,   0, 0 },
  635.      { MIT_END, MIS_TEXT,      0, IDM_HIDE_CONTROLS,    0, 0 },
  636.      { MIT_END, MIS_TEXT,      0, IDM_CONFIGURE,        0, 0 },
  637.      { MIT_END, MIS_TEXT,      0, IDM_RESETLOAD,        0, 0 },
  638.      { MIT_END, MIS_TEXT,      0, IDM_COPY,             0, 0 },
  639.   } ;
  640.  
  641.   for ( int i=0; i<sizeof(MenuItems)/sizeof(MenuItems[0]); i++ ) {
  642.      ResourceString MenuText ( Data->Library->QueryHandle(), i+IDS_SAVE_APPLICATION ) ;
  643.      AddSysMenuItem ( Frame, MenuItems+i, PSZ(MenuText) ) ;
  644.   } /* endfor */
  645.  
  646.   AddSysMenuItem ( Frame, &MenuSeparator, 0 ) ;
  647.  
  648.  /***************************************************************************
  649.   * Add 'About' to the system menu.                                         *
  650.   ***************************************************************************/
  651.  
  652.   static MENUITEM MenuAbout =
  653.     { MIT_END, MIS_TEXT, 0, IDM_ABOUT, 0, 0 } ;
  654.  
  655.   ResourceString AboutText ( Data->Library->QueryHandle(), IDS_ABOUT ) ;
  656.  
  657.   AddSysMenuItem ( Frame, &MenuAbout, PSZ(AboutText) ) ;
  658.  
  659.  /***************************************************************************
  660.   * Add 'Help' to the system menu.                                          *
  661.   ***************************************************************************/
  662.  
  663.   static MENUITEM MenuHelp =
  664.     { MIT_END, MIS_HELP, 0, 0, 0, 0 } ;
  665.  
  666.   ResourceString HelpText ( Data->Library->QueryHandle(), IDS_HELP ) ;
  667.  
  668.   AddSysMenuItem ( Frame, &MenuHelp, PSZ(HelpText) ) ;
  669.  
  670.  /***************************************************************************
  671.   * Start the new load meter.                                               *
  672.   ***************************************************************************/
  673.  
  674.   CounterThreadEvent.Reset ( ) ;
  675.   Data->CounterParms.Active = TRUE ;
  676.   Data->CounterTID = StartThread ( "CounterThread", CounterThread, 0x3000, &Data->CounterParms ) ;
  677.   DosSuspendThread ( Data->CounterTID ) ;
  678.   DosSetPriority ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->CounterTID ) ;
  679.  
  680.   Data->IniData.IdleCount = 0 ;
  681.   Data->CounterParms.Counter = 0 ;
  682.  
  683.   if ( Data->IniData.Items[ITEM_CPULOAD].pItem->QueryFlag() )
  684.      DosResumeThread ( Data->CounterTID ) ;
  685.  
  686.   MonitorThreadEvent.Reset ( ) ;
  687.   Data->MonitorParms.Active = TRUE ;
  688.   Data->MonitorParms.Counter = & Data->CounterParms.Counter ;
  689.   Data->MonitorParms.Interval = & Data->IniData.TimerInterval ;
  690.   Data->MonitorParms.Priority = & Data->IniData.MonitorPriority ;
  691.   Data->MonitorParms.Owner = hwnd ;
  692.   Data->MonitorTID = StartThread ( "MonitorLoopThread", MonitorLoopThread, 0x3000, &Data->MonitorParms ) ;
  693.  
  694.  /***************************************************************************
  695.   * Add the program to the system task list.                                *
  696.   ***************************************************************************/
  697.  
  698.   ResourceString Title ( Data->Library->QueryHandle(), IDS_TITLE ) ;
  699.   Add2TaskList ( Frame, PSZ(Title) ) ;
  700.  
  701.  /***************************************************************************
  702.   * Hide the controls if so configured.                                     *
  703.   ***************************************************************************/
  704.  
  705.   #ifdef DEBUG
  706.   Log ( "Create: HideControls:%s, Minimize:%s.",
  707.      Data->IniData.HideControls ? "TRUE" : "FALSE",
  708.      Data->IniData.Position.fl & SWP_MINIMIZE ? "TRUE" : "FALSE" ) ;
  709.   #endif
  710.  
  711.   if ( Data->IniData.HideControls AND NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) ) {
  712.      #ifdef DEBUG
  713.      Log ( "Create: Hiding controls." ) ;
  714.      #endif
  715.      HideControls ( TRUE, Frame, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  716.   } /* endif */
  717.  
  718.  /***************************************************************************
  719.   * Position & size the window.  For some reason, we must move and size     *
  720.   *   the window to the saved position before applying the resizing         *
  721.   *   function as fine-tuning.  Maybe the positioning request fails if      *
  722.   *   the window has no size?                                               *
  723.   ***************************************************************************/
  724.  
  725.   #ifdef DEBUG
  726.   Log ( "Create: Setting window position to %i,%i (%ix%i).",
  727.      Data->IniData.Position.x, Data->IniData.Position.y,
  728.      Data->IniData.Position.cx, Data->IniData.Position.cy ) ;
  729.   #endif
  730.  
  731.   WinSetWindowPos ( Frame, HWND_BOTTOM,
  732.      Data->IniData.Position.x, Data->IniData.Position.y,
  733.      Data->IniData.Position.cx, Data->IniData.Position.cy,
  734.      SWP_SIZE | SWP_MOVE | SWP_ZORDER |
  735.      ( Data->IniData.Position.fl & SWP_MINIMIZE ) |
  736.      ( Data->IniData.Position.fl & SWP_RESTORE ) ) ;
  737.  
  738.  /***************************************************************************
  739.   * Adjust the window size to suit the displayable items.                   *
  740.   ***************************************************************************/
  741.  
  742.   ResizeWindow ( hwnd ) ;
  743.  
  744.  /***************************************************************************
  745.   * Determine our font size.                                                *
  746.   ***************************************************************************/
  747.  
  748.   HPS hPS = WinGetPS ( hwnd ) ;
  749.   RECTL Rectangle ;
  750.   WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  751.   WinDrawText ( hPS, 1, PSZ(" "), &Rectangle, 0, 0, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  752.   Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  753.   Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  754.   WinReleasePS ( hPS ) ;
  755.  
  756.  /***************************************************************************
  757.   * Now that the window's in order, make it visible.                        *
  758.   ***************************************************************************/
  759.  
  760.   WinShowWindow ( Frame, TRUE ) ;
  761.  
  762.  /***************************************************************************
  763.   * Success?  Return no error.                                              *
  764.   ***************************************************************************/
  765.  
  766.   return ( 0 ) ;
  767. }
  768.  
  769. /****************************************************************************
  770.  *                                                                          *
  771.  *      Destroy main window.                                                *
  772.  *                                                                          *
  773.  ****************************************************************************/
  774.  
  775. STATIC MRESULT APIENTRY Destroy ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  776.  
  777.  /***************************************************************************
  778.   * Find the instance data.                                                 *
  779.   ***************************************************************************/
  780.  
  781.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  782.  
  783.  /***************************************************************************
  784.   * Kill the extra threads.                                                 *
  785.   ***************************************************************************/
  786.  
  787.   DosResumeThread ( Data->MonitorTID ) ;
  788.   Data->MonitorParms.Active = FALSE ;
  789.   MonitorThreadEvent.Wait ( 10000 ) ;
  790.  
  791.   DosResumeThread ( Data->CounterTID ) ;
  792.   Data->CounterParms.Active = FALSE ;
  793.   DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, Data->CounterTID ) ;
  794.   CounterThreadEvent.Wait ( 10000 ) ;
  795.  
  796.  /***************************************************************************
  797.   * Destroy the DDE Server object.                                          *
  798.   ***************************************************************************/
  799.  
  800.   delete Data->pDdeServer ;
  801.  
  802.  /***************************************************************************
  803.   * Release the instance memory.                                            *
  804.   ***************************************************************************/
  805.  
  806.   free ( Data ) ;
  807.  
  808.  /***************************************************************************
  809.   * We're done.                                                             *
  810.   ***************************************************************************/
  811.  
  812.   return ( MRFROMSHORT ( 0 ) ) ;
  813. }
  814.  
  815. /****************************************************************************
  816.  *                                                                          *
  817.  *      Process window resize message.                                      *
  818.  *                                                                          *
  819.  ****************************************************************************/
  820.  
  821. STATIC MRESULT APIENTRY Size ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  822.  
  823.   #ifdef DEBUG
  824.   Log ( "Size: Started." ) ;
  825.   #endif
  826.  
  827.  /***************************************************************************
  828.   * Find the instance data.                                                 *
  829.   ***************************************************************************/
  830.  
  831.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  832.  
  833.  /***************************************************************************
  834.   * Find out the window's new position and size.                            *
  835.   ***************************************************************************/
  836.  
  837.   HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  838.  
  839.   SWP Position ;
  840.   WinQueryWindowPos ( Frame, &Position ) ;
  841.  
  842.   if (   NOT ( Position.fl & SWP_HIDE     )
  843.      AND NOT ( Position.fl & SWP_MINIMIZE )
  844.      AND NOT ( Position.fl & SWP_MAXIMIZE ) ) {
  845.  
  846.      Data->IniData.Position.x = Position.x ;
  847.      Data->IniData.Position.y = Position.y ;
  848.  
  849.      Data->IniData.Position.cx = Position.cx ;
  850.      Data->IniData.Position.cy = Position.cy ;
  851.  
  852.      #ifdef DEBUG
  853.      Log ( "Size: Window position set to %i,%i (%ix%i).",
  854.         Data->IniData.Position.x, Data->IniData.Position.y,
  855.         Data->IniData.Position.cx, Data->IniData.Position.cy ) ;
  856.      #endif
  857.  
  858.   } /* endif */
  859.  
  860.  /***************************************************************************
  861.   * If hiding the controls . . .                                            *
  862.   ***************************************************************************/
  863.  
  864.   if ( Data->IniData.HideControls ) {
  865.  
  866.    /*************************************************************************
  867.     * If changing to or from minimized state . . .                          *
  868.     *************************************************************************/
  869.  
  870.     if ( ( Position.fl & SWP_MINIMIZE ) != ( Data->IniData.Position.fl & SWP_MINIMIZE ) ) {
  871.  
  872.      /***********************************************************************
  873.       * Hide the controls if no longer minimized.                           *
  874.       ***********************************************************************/
  875.  
  876.       HideControls ( NOT ( Position.fl & SWP_MINIMIZE ),
  877.         Frame, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  878.  
  879.     }
  880.   }
  881.  
  882.   Data->IniData.Position.fl = Position.fl ;
  883.  
  884.  /***************************************************************************
  885.   * We're done.                                                             *
  886.   ***************************************************************************/
  887.  
  888.   #ifdef DEBUG
  889.   Log ( "Size: Done." ) ;
  890.   #endif
  891.  
  892.   return ( 0 ) ;
  893. }
  894.  
  895. /****************************************************************************
  896.  *                                                                          *
  897.  *      Process SAVE APPLICATION message.                                   *
  898.  *                                                                          *
  899.  ****************************************************************************/
  900.  
  901. STATIC MRESULT APIENTRY SaveApplication ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  902.  
  903.  /***************************************************************************
  904.   * Find the instance data.                                                 *
  905.   ***************************************************************************/
  906.  
  907.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  908.  
  909.  /***************************************************************************
  910.   * Call function to put all profile data out to the system.                *
  911.   ***************************************************************************/
  912.  
  913.   PutIniData ( Data->IniFile->QueryHandle(), &Data->IniData ) ;
  914.  
  915.  /***************************************************************************
  916.   * We're done.  Let the system complete default processing.                *
  917.   ***************************************************************************/
  918.  
  919.   return ( WinDefWindowProc ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ) ;
  920. }
  921.  
  922. /****************************************************************************
  923.  *                                                                          *
  924.  *      Repaint entire window.                                              *
  925.  *                                                                          *
  926.  ****************************************************************************/
  927.  
  928. STATIC MRESULT APIENTRY Paint ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  929.  
  930.  /***************************************************************************
  931.   * Find the instance data.                                                 *
  932.   ***************************************************************************/
  933.  
  934.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  935.  
  936.  /***************************************************************************
  937.   * Get presentation space and make it use RGB colors.                      *
  938.   ***************************************************************************/
  939.  
  940.   HPS hPS = WinBeginPaint ( hwnd, 0, 0 ) ;
  941.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0, 0, 0 ) ;
  942.   GpiSetCp ( hPS, Data->CodePage ) ;
  943.  
  944.  /***************************************************************************
  945.   * Get font information for later use with Copy command.                   *
  946.   ***************************************************************************/
  947.  
  948.   GpiQueryFontMetrics ( hPS, sizeof(Data->FontMetrics), &Data->FontMetrics ) ;
  949.   Data->CharMode = GpiQueryCharMode ( hPS ) ;
  950.   GpiQueryCharBox ( hPS, &Data->CharBox ) ;
  951.  
  952.  /***************************************************************************
  953.   * Clear the window.                                                       *
  954.   ***************************************************************************/
  955.  
  956.   RECTL Rectangle ;
  957.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  958.  
  959.   GpiMove ( hPS, (PPOINTL) &Rectangle.xLeft ) ;
  960.   GpiSetColor ( hPS, Data->IniData.BackColor ) ;
  961.   GpiBox ( hPS, DRO_FILL, (PPOINTL) &Rectangle.xRight, 0, 0 ) ;
  962.  
  963.  /***************************************************************************
  964.   * Release presentation space.                                             *
  965.   ***************************************************************************/
  966.  
  967.   WinEndPaint ( hPS ) ;
  968.  
  969.  /***************************************************************************
  970.   * Update the window and return.                                           *
  971.   ***************************************************************************/
  972.  
  973.   UpdateWindow ( hwnd, Data, TRUE ) ;
  974.  
  975.   return ( 0 ) ;
  976. }
  977.  
  978. /****************************************************************************
  979.  *                                                                          *
  980.  *      Process requests for menu initialization.                           *
  981.  *                                                                          *
  982.  ****************************************************************************/
  983.  
  984. static MRESULT APIENTRY InitMenu ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  985.  
  986.  /***************************************************************************
  987.   * Find the instance data.                                                 *
  988.   ***************************************************************************/
  989.  
  990.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  991.  
  992.  /***************************************************************************
  993.   * Get the message data.                                                   *
  994.   ***************************************************************************/
  995.  
  996.   int MenuID = SHORT1FROMMP ( mp1 ) ;
  997.   HWND Menu = HWNDFROMMP ( mp2 ) ;
  998.  
  999.  /***************************************************************************
  1000.   * Process according to which menu's about to be displayed.                *
  1001.   ***************************************************************************/
  1002.  
  1003.   switch ( MenuID ) {
  1004.  
  1005.      case FID_SYSMENU:
  1006.      case FID_MENU:
  1007.      case IDM_MENU: {
  1008.         CheckMenuItem ( Menu, IDM_HIDE_CONTROLS, Data->IniData.HideControls ) ;
  1009.         break ; }
  1010.  
  1011.   }
  1012.  
  1013.  /***************************************************************************
  1014.   * We're done.                                                             *
  1015.   ***************************************************************************/
  1016.  
  1017.   return ( MRFROMSHORT ( 0 ) ) ;
  1018. }
  1019.  
  1020. /****************************************************************************
  1021.  *                                                                          *
  1022.  *      Process commands received by Main Window                            *
  1023.  *                                                                          *
  1024.  ****************************************************************************/
  1025.  
  1026. STATIC MRESULT APIENTRY Command ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1027.  
  1028.  /***************************************************************************
  1029.   * Dispatch all other commands through the method table.                   *
  1030.   ***************************************************************************/
  1031.  
  1032.   static METHOD Methods [] = {
  1033.     { IDM_SAVE_APPLICATION, SaveApplication },
  1034.     { IDM_RESET_DEFAULTS,   ResetDefaults   },
  1035.     { IDM_HIDE_CONTROLS,    HideControlsCmd },
  1036.     { IDM_CONFIGURE,        Configure       },
  1037.     { IDM_RESETLOAD,        ResetLoad       },
  1038.     { IDM_COPY,             Copy            },
  1039.     { IDM_EXIT,             Exit            },
  1040.     { IDM_ABOUT,            About           },
  1041.   } ;
  1042.  
  1043.   return ( DispatchMessage ( hwnd, SHORT1FROMMP(mp1), mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), 0 ) ) ;
  1044. }
  1045.  
  1046. /****************************************************************************
  1047.  *                                                                          *
  1048.  *      Process Reset Defaults menu command.                                *
  1049.  *                                                                          *
  1050.  ****************************************************************************/
  1051.  
  1052. STATIC MRESULT APIENTRY ResetDefaults ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1053.  
  1054.  /***************************************************************************
  1055.   * Find the instance data.                                                 *
  1056.   ***************************************************************************/
  1057.  
  1058.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1059.  
  1060.  /***************************************************************************
  1061.   * Reset all profile data for this program.                                *
  1062.   ***************************************************************************/
  1063.  
  1064.   PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), 0, 0, 0 ) ;
  1065.  
  1066.  /***************************************************************************
  1067.   * Reset the program's presentation parameters.                            *
  1068.   ***************************************************************************/
  1069.  
  1070.   WinRemovePresParam ( hwnd, PP_FONTNAMESIZE ) ;
  1071.   WinRemovePresParam ( hwnd, PP_FOREGROUNDCOLOR ) ;
  1072.   WinRemovePresParam ( hwnd, PP_BACKGROUNDCOLOR ) ;
  1073.  
  1074.  /***************************************************************************
  1075.   * Done.                                                                   *
  1076.   ***************************************************************************/
  1077.  
  1078.   return ( MRFROMSHORT ( 0 ) ) ;
  1079. }
  1080.  
  1081. /****************************************************************************
  1082.  *                                                                          *
  1083.  *      Process Hide Controls menu command.                                 *
  1084.  *                                                                          *
  1085.  ******************m*********************************************************/
  1086.  
  1087. STATIC MRESULT APIENTRY HideControlsCmd ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1088.  
  1089.  /***************************************************************************
  1090.   * Find the instance data.                                                 *
  1091.   ***************************************************************************/
  1092.  
  1093.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1094.  
  1095.  /***************************************************************************
  1096.   * Toggle the Hide Controls setting.                                       *
  1097.   ***************************************************************************/
  1098.  
  1099.   Data->IniData.HideControls = Data->IniData.HideControls ? FALSE : TRUE ;
  1100.   Data->IniData.fHideControls = TRUE ;
  1101.  
  1102.  /***************************************************************************
  1103.   * Get the frame handle.                                                   *
  1104.   ***************************************************************************/
  1105.  
  1106.   HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1107.  
  1108.  /***************************************************************************
  1109.   * If not minimized right now, hide or reveal the controls.                *
  1110.   ***************************************************************************/
  1111.  
  1112.   if ( NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) ) {
  1113.     HideControls ( Data->IniData.HideControls,
  1114.       Frame, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  1115.   }
  1116.  
  1117.  /***************************************************************************
  1118.   * Done.                                                                   *
  1119.   ***************************************************************************/
  1120.  
  1121.   return ( MRFROMSHORT ( 0 ) ) ;
  1122. }
  1123.  
  1124. /****************************************************************************
  1125.  *                                                                          *
  1126.  *      Process Configure command.                                          *
  1127.  *                                                                          *
  1128.  ****************************************************************************/
  1129.  
  1130. STATIC MRESULT APIENTRY Configure ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1131.  
  1132.  /***************************************************************************
  1133.   * Find the instance data.                                                 *
  1134.   ***************************************************************************/
  1135.  
  1136.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1137.  
  1138.  /***************************************************************************
  1139.   * Invoke the Configure dialog.  If cancelled, just return.                *
  1140.   ***************************************************************************/
  1141.  
  1142.   CONFIG_PARMS Parms ;
  1143.   Parms.HideControls        = Data->IniData.HideControls ;
  1144.   Parms.Float               = Data->IniData.Float ;
  1145.   Parms.Animate             = Data->IniData.Animate ;
  1146.   Parms.ShowFileSystemNames = Data->IniData.ShowFileSystemNames ;
  1147.   Parms.ShowDiskLabels      = Data->IniData.ShowDiskLabels ;
  1148.   Parms.ShowSeconds         = Data->IniData.ShowSeconds ;
  1149.   Parms.ShowK               = Data->IniData.ShowK ;
  1150.   Parms.MonitorPriority     = Data->IniData.MonitorPriority ;
  1151.   Parms.TimerInterval       = Data->IniData.TimerInterval ;
  1152.   Parms.AnchorCorner        = Data->IniData.AnchorCorner ;
  1153.   Parms.ItemCount           = Data->IniData.ItemCount ;
  1154.  
  1155.   for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  1156.      Item *pItem = Data->IniData.Items[i].pItem ;
  1157.      Parms.ItemFlags[i] = pItem->QueryFlag () ;
  1158.      strcpy ( Parms.CurrentLabels[i], PCHAR(pItem->QueryCurrentLabel()) ) ;
  1159.      strcpy ( Parms.DefaultLabels[i], PCHAR(pItem->QueryDefaultLabel()) ) ;
  1160.   } /* endfor */
  1161.  
  1162.   if ( WinDlgBox ( HWND_DESKTOP, hwnd, PFNWP(ConfigureProcessor),
  1163.      Data->Library->QueryHandle(), IDD_CONFIGURE, &Parms ) == FALSE )
  1164.   {
  1165.      return ( MRFROMSHORT ( 0 ) ) ;
  1166.   }
  1167.  
  1168.  /***************************************************************************
  1169.   * Save the new monitor priority.                                          *
  1170.   ***************************************************************************/
  1171.  
  1172.   Data->IniData.fMonitorPriority = TRUE ;
  1173.   Data->IniData.MonitorPriority = BYTE ( Parms.MonitorPriority ) ;
  1174.  
  1175.  /***************************************************************************
  1176.   * Save the new timer interval.                                            *
  1177.   ***************************************************************************/
  1178.  
  1179.   Data->IniData.fTimerInterval = TRUE ;
  1180.   Data->IniData.TimerInterval = USHORT ( Parms.TimerInterval ) ;
  1181.  
  1182.  /***************************************************************************
  1183.   * Save the float-to-top flag.                                             *
  1184.   ***************************************************************************/
  1185.  
  1186.   Data->IniData.fFloat = TRUE ;
  1187.   Data->IniData.Float = Parms.Float ;
  1188.  
  1189.  /***************************************************************************
  1190.   * Save the window animate flag.                                           *
  1191.   ***************************************************************************/
  1192.  
  1193.   Data->IniData.fAnimate = TRUE ;
  1194.   Data->IniData.Animate = Parms.Animate ;
  1195.  
  1196.  /***************************************************************************
  1197.   * Save the anchor corner flag.                                            *
  1198.   ***************************************************************************/
  1199.  
  1200.   Data->IniData.fAnchorCorner = TRUE ;
  1201.   Data->IniData.AnchorCorner = Parms.AnchorCorner ;
  1202.  
  1203.  /***************************************************************************
  1204.   * Save the hide controls flag, and adjust the window if it changed.       *
  1205.   ***************************************************************************/
  1206.  
  1207.   Data->IniData.fHideControls = TRUE ;
  1208.   if ( Data->IniData.HideControls != Parms.HideControls ) {
  1209.      HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1210.      Data->IniData.HideControls = Parms.HideControls ;
  1211.      if ( NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  1212.         HideControls ( Data->IniData.HideControls, FrameWindow, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  1213.   } /* endif */
  1214.  
  1215.  /***************************************************************************
  1216.   * If CPU load monitoring has changed, start/stop the monitoring thread.   *
  1217.   ***************************************************************************/
  1218.  
  1219.   if ( Parms.ItemFlags[ITEM_CPULOAD] != Data->IniData.Items[ITEM_CPULOAD].pItem->QueryFlag() )
  1220.      if ( Parms.ItemFlags[ITEM_CPULOAD] )
  1221.         DosResumeThread ( Data->CounterTID ) ;
  1222.      else
  1223.         DosSuspendThread ( Data->CounterTID ) ;
  1224.  
  1225.  /***************************************************************************
  1226.   * Determine if the display item list has changed.  If not, return.        *
  1227.   ***************************************************************************/
  1228.  
  1229.   BOOL ItemsChanged = FALSE ;
  1230.   for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  1231.      Item *pItem = Data->IniData.Items[i].pItem ;
  1232.      if ( Parms.ItemFlags[i] != pItem->QueryFlag() ) {
  1233.         ItemsChanged = TRUE ;
  1234.         break ;
  1235.      } /* endif */
  1236.      if ( strcmp ( Parms.CurrentLabels[i], PCHAR(pItem->QueryCurrentLabel()) ) ) {
  1237.         ItemsChanged = TRUE ;
  1238.         break ;
  1239.      } /* endif */
  1240.   } /* endfor */
  1241.  
  1242.   if ( NOT ItemsChanged
  1243.      AND ( Data->IniData.ShowFileSystemNames == Parms.ShowFileSystemNames )
  1244.      AND ( Data->IniData.ShowDiskLabels == Parms.ShowDiskLabels )
  1245.      AND ( Data->IniData.ShowSeconds == Parms.ShowSeconds )
  1246.      AND ( Data->IniData.ShowK == Parms.ShowK ) ) {
  1247.      return ( MRFROMSHORT ( 0 ) ) ;
  1248.   } /* endif */
  1249.  
  1250.  /***************************************************************************
  1251.   * Save the show file-system names flag.                                   *
  1252.   ***************************************************************************/
  1253.  
  1254.   Data->IniData.fShowFileSystemNames = TRUE ;
  1255.   Data->IniData.ShowFileSystemNames = Parms.ShowFileSystemNames ;
  1256.  
  1257.   for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  1258.      Item *pItem = Data->IniData.Items[i].pItem ;
  1259.      ((DriveFree*)pItem)->SetShowFileSystemName ( Data->IniData.ShowFileSystemNames ) ;
  1260.   } /* endfor */
  1261.  
  1262.  /***************************************************************************
  1263.   * Save the show disk labels flag.                                         *
  1264.   ***************************************************************************/
  1265.  
  1266.   Data->IniData.fShowDiskLabels = TRUE ;
  1267.   Data->IniData.ShowDiskLabels = Parms.ShowDiskLabels ;
  1268.  
  1269.   for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  1270.      Item *pItem = Data->IniData.Items[i].pItem ;
  1271.      ((DriveFree*)pItem)->SetShowDiskLabel ( Data->IniData.ShowDiskLabels ) ;
  1272.   } /* endfor */
  1273.  
  1274.  /***************************************************************************
  1275.   * Save the show seconds flag.                                             *
  1276.   ***************************************************************************/
  1277.  
  1278.   Data->IniData.fShowSeconds = TRUE ;
  1279.   Data->IniData.ShowSeconds = Parms.ShowSeconds ;
  1280.  
  1281.   ((Clock*)Data->IniData.Items[ITEM_CLOCK].pItem)->SetShowSeconds ( Data->IniData.ShowSeconds ) ;
  1282.   ((ElapsedTime*)Data->IniData.Items[ITEM_ELAPSEDTIME].pItem)->SetShowSeconds ( Data->IniData.ShowSeconds ) ;
  1283.  
  1284.  /***************************************************************************
  1285.   * Save the show 'K' flag.                                                 *
  1286.   ***************************************************************************/
  1287.  
  1288.   Data->IniData.fShowK = TRUE ;
  1289.   Data->IniData.ShowK = Parms.ShowK ;
  1290.  
  1291.   ((MemoryFree *)Data->IniData.Items[ITEM_MEMORYFREE   ].pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1292.   ((VirtualFree*)Data->IniData.Items[ITEM_VIRTUALFREE  ].pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1293.   ((SwapFree   *)Data->IniData.Items[ITEM_SWAPDISKFREE ].pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1294.   ((SwapSize   *)Data->IniData.Items[ITEM_SWAPFILESIZE ].pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1295.   ((SwapSlack  *)Data->IniData.Items[ITEM_SWAPFILESLACK].pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1296.   ((SpoolSize  *)Data->IniData.Items[ITEM_SPOOLFILESIZE].pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1297.   ((TotalFree  *)Data->IniData.Items[ITEM_TOTALFREE    ].pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1298.  
  1299.   for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  1300.      Item *pItem = Data->IniData.Items[i].pItem ;
  1301.      ((DriveFree*)pItem)->SetShowK ( Data->IniData.ShowK ) ;
  1302.   } /* endfor */
  1303.  
  1304.  /***************************************************************************
  1305.   * Save the new item flags.                                                *
  1306.   ***************************************************************************/
  1307.  
  1308.   for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  1309.      Item *pItem = Data->IniData.Items[i].pItem ;
  1310.      if ( Parms.ItemFlags[i] )
  1311.         pItem->SetFlag ( ) ;
  1312.      else
  1313.         pItem->ResetFlag ( ) ;
  1314.      pItem->SetLabel ( Parms.CurrentLabels[i] ) ;
  1315.   } /* endif */
  1316.  
  1317.  /***************************************************************************
  1318.   * Resize the display window.                                              *
  1319.   ***************************************************************************/
  1320.  
  1321.   ResizeWindow ( hwnd ) ;
  1322.  
  1323.  /***************************************************************************
  1324.   * Done.                                                                   *
  1325.   ***************************************************************************/
  1326.  
  1327.   return ( MRFROMSHORT ( 0 ) ) ;
  1328. }
  1329.  
  1330. /****************************************************************************
  1331.  *                                                                          *
  1332.  *      Process Reset Load menu command.                                    *
  1333.  *                                                                          *
  1334.  ****************************************************************************/
  1335.  
  1336. STATIC MRESULT APIENTRY ResetLoad ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1337.  
  1338.  /***************************************************************************
  1339.   * Find the instance data.                                                 *
  1340.   ***************************************************************************/
  1341.  
  1342.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1343.  
  1344.  /***************************************************************************
  1345.   * Shut down the CPU load meter threads.                                   *
  1346.   ***************************************************************************/
  1347.  
  1348.   DosResumeThread ( Data->MonitorTID ) ;
  1349.   Data->MonitorParms.Active = FALSE ;
  1350.   MonitorThreadEvent.Wait ( 10000 ) ;
  1351.  
  1352.   DosResumeThread ( Data->CounterTID ) ;
  1353.   Data->CounterParms.Active = FALSE ;
  1354.   DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, Data->CounterTID ) ;
  1355.   CounterThreadEvent.Wait ( 10000 ) ;
  1356.  
  1357.  /***************************************************************************
  1358.   * Reset the load meter.                                                   *
  1359.   ***************************************************************************/
  1360.  
  1361.   Data->IniData.MaxCount = CalibrateLoadMeter ( &Data->CounterParms ) ;
  1362.   Data->IniData.MaxCount = (ULONG) max ( 1, Data->IniData.MaxCount ) ;
  1363.  
  1364.  /***************************************************************************
  1365.   * Restart the CPU load meter threads.                                     *
  1366.   ***************************************************************************/
  1367.  
  1368.   CounterThreadEvent.Reset ( ) ;
  1369.   Data->CounterParms.Active = TRUE ;
  1370.   Data->CounterTID = StartThread ( "CounterThread", CounterThread, 0x3000, &Data->CounterParms ) ;
  1371.   DosSuspendThread ( Data->CounterTID ) ;
  1372.   DosSetPriority ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->CounterTID ) ;
  1373.  
  1374.   Data->IniData.IdleCount = 0 ;
  1375.   Data->CounterParms.Counter = 0 ;
  1376.  
  1377.   if ( Data->IniData.Items[ITEM_CPULOAD].pItem->QueryFlag() )
  1378.      DosResumeThread ( Data->CounterTID ) ;
  1379.  
  1380.   MonitorThreadEvent.Reset ( ) ;
  1381.   Data->MonitorParms.Active = TRUE ;
  1382.   Data->MonitorParms.Counter = & Data->CounterParms.Counter ;
  1383.   Data->MonitorParms.Interval = & Data->IniData.TimerInterval ;
  1384.   Data->MonitorParms.Priority = & Data->IniData.MonitorPriority ;
  1385.   Data->MonitorParms.Owner = hwnd ;
  1386.   Data->MonitorTID = StartThread ( "MonitorLoopThread", MonitorLoopThread, 0x3000, &Data->MonitorParms ) ;
  1387.  
  1388.  /***************************************************************************
  1389.   * Done.                                                                   *
  1390.   ***************************************************************************/
  1391.  
  1392.   return ( MRFROMSHORT ( 0 ) ) ;
  1393. }
  1394.  
  1395. /****************************************************************************
  1396.  *                                                                          *
  1397.  *      Process Copy command.                                               *
  1398.  *                                                                          *
  1399.  ****************************************************************************/
  1400.  
  1401. STATIC MRESULT APIENTRY Copy ( HWND Window, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1402.  
  1403.   /**************************************************************************
  1404.    * Find the instance data.                                                *
  1405.    **************************************************************************/
  1406.  
  1407.    PDATA Data = PDATA ( WinQueryWindowPtr ( Window, QWL_USER ) ) ;
  1408.  
  1409.   /**************************************************************************
  1410.    * Review all items.  Display those changed, or all.                      *
  1411.    **************************************************************************/
  1412.  
  1413.    char *Buffer = (char*) malloc ( ( ITEM_BASE_COUNT + MAX_DRIVES ) * ( Data->MaxColumns + 1 ) ) ;
  1414.    Buffer [0] = 0 ;
  1415.  
  1416.    for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  1417.       Item *pItem = Data->IniData.Items[i].pItem ;
  1418.       if ( pItem->QueryFlag() ) {
  1419.          pItem->FormatLine ( Buffer, Data->MaxColumns ) ;
  1420.       } /* endif */
  1421.    } /* endfor */
  1422.  
  1423.    char *ClipText ;
  1424.    DosAllocSharedMem ( PPVOID(&ClipText), 0, strlen(Buffer)+1,
  1425.       PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) ;
  1426.    strcpy ( ClipText, Buffer ) ;
  1427.    free ( Buffer ) ;
  1428.  
  1429.   /**************************************************************************
  1430.    * Create bitmap image of current window.                                 *
  1431.    **************************************************************************/
  1432.  
  1433.    static PSZ pszData [2] = { 0, PSZ("Display") } ;
  1434.    HDC MemoryDC = DevOpenDC ( Data->Proc->QueryAnchor(), OD_MEMORY, PSZ("*"), 2, PDEVOPENDATA(pszData), 0 ) ;
  1435.  
  1436.    SIZEL PageSize = { 0, 0 } ;
  1437.    HPS hPS = GpiCreatePS ( Data->Proc->QueryAnchor(), MemoryDC, &PageSize, PU_PELS | GPIA_ASSOC | GPIT_MICRO ) ;
  1438.    GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0, 0, 0 ) ;
  1439.    GpiSetCp ( hPS, Data->CodePage ) ;
  1440.  
  1441.    LONG alData [2] ;
  1442.    GpiQueryDeviceBitmapFormats ( hPS, 2, alData ) ;
  1443.  
  1444.    RECTL Rectangle ;
  1445.    WinQueryWindowRect ( Window, &Rectangle ) ;
  1446.  
  1447.    BITMAPINFOHEADER2 BitmapHeader ;
  1448.    memset ( &BitmapHeader, 0, sizeof(BitmapHeader) ) ;
  1449.    BitmapHeader.cbFix = 16 ;
  1450.    BitmapHeader.cx = Rectangle.xRight - Rectangle.xLeft ;
  1451.    BitmapHeader.cy = Rectangle.yTop - Rectangle.yBottom ;
  1452.    BitmapHeader.cPlanes = USHORT ( alData[0] ) ;
  1453.    BitmapHeader.cBitCount = USHORT ( alData[1] ) ;
  1454.  
  1455.    HBITMAP Bitmap = GpiCreateBitmap ( hPS, &BitmapHeader, 0, 0, 0 ) ;
  1456.    GpiSetBitmap ( hPS, Bitmap ) ;
  1457.  
  1458.    FATTRS FontAttributes ;
  1459.    memset ( &FontAttributes, 0, sizeof(FontAttributes) ) ;
  1460.    strcpy ( FontAttributes.szFacename, Data->FontMetrics.szFacename ) ;
  1461.    FontAttributes.usRecordLength  = sizeof(FontAttributes) ;
  1462.    FontAttributes.usCodePage      = Data->FontMetrics.usCodePage ;
  1463.    FontAttributes.lMaxBaselineExt = Data->FontMetrics.lMaxBaselineExt ;
  1464.    FontAttributes.lAveCharWidth   = Data->FontMetrics.lAveCharWidth ;
  1465.  
  1466.    GpiCreateLogFont ( hPS, 0, 1, &FontAttributes ) ;
  1467.    GpiSetCharSet ( hPS, 1 ) ;
  1468.    GpiSetCharMode ( hPS, Data->CharMode ) ;
  1469.    if ( Data->CharMode == CM_MODE3 )
  1470.       GpiSetCharBox ( hPS, &Data->CharBox ) ;
  1471.  
  1472.    GpiMove ( hPS, PPOINTL(&Rectangle.xLeft) ) ;
  1473.    GpiSetColor ( hPS, Data->IniData.BackColor ) ;
  1474.    GpiBox ( hPS, DRO_FILL, PPOINTL(&Rectangle.xRight), 0, 0 ) ;
  1475.  
  1476.    int Count = 0 ;
  1477.    for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  1478.       Item *pItem = Data->IniData.Items[i].pItem ;
  1479.       if ( pItem->QueryFlag() ) {
  1480.          Count ++ ;
  1481.       } /* endif */
  1482.    } /* endfor */
  1483.  
  1484.    Rectangle.xLeft += Data->Width / 2 ;
  1485.    Rectangle.xRight -= Data->Width / 2 ;
  1486.  
  1487.    Rectangle.yBottom = Data->Height * ( Count - 1 ) ;
  1488.    Rectangle.yTop = Rectangle.yBottom + Data->Height ;
  1489.  
  1490.    for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  1491.       Item *pItem = Data->IniData.Items[i].pItem ;
  1492.       if ( pItem->QueryFlag() ) {
  1493.          pItem->Repaint ( hPS, Rectangle, Data->IniData.TextColor, Data->IniData.BackColor, TRUE ) ;
  1494.          Rectangle.yBottom -= Data->Height ;
  1495.          Rectangle.yTop    -= Data->Height ;
  1496.       } /* endif */
  1497.    } /* endfor */
  1498.  
  1499.    GpiDestroyPS ( hPS ) ;
  1500.    DevCloseDC ( MemoryDC ) ;
  1501.  
  1502.   /**************************************************************************
  1503.    * Empty the clipboard and give it new data.                              *
  1504.    **************************************************************************/
  1505.  
  1506.    if ( WinOpenClipbrd ( Data->Proc->QueryAnchor() ) ) {
  1507.       WinEmptyClipbrd ( Data->Proc->QueryAnchor() ) ;
  1508.       WinSetClipbrdData ( Data->Proc->QueryAnchor(), ULONG(ClipText), CF_TEXT, CFI_POINTER ) ;
  1509.       WinSetClipbrdData ( Data->Proc->QueryAnchor(), ULONG(Bitmap), CF_BITMAP, CFI_HANDLE ) ;
  1510.       WinCloseClipbrd ( Data->Proc->QueryAnchor() ) ;
  1511.    } else {
  1512.       DosFreeMem ( ClipText ) ;
  1513.    } /* endif */
  1514.  
  1515.   /**************************************************************************
  1516.    * Done.                                                                  *
  1517.    **************************************************************************/
  1518.  
  1519.    return ( MRFROMSHORT ( 0 ) ) ;
  1520. }
  1521.  
  1522. /****************************************************************************
  1523.  *                                                                          *
  1524.  *      Process About menu command.                                         *
  1525.  *                                                                          *
  1526.  ****************************************************************************/
  1527.  
  1528. STATIC MRESULT APIENTRY About ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1529.  
  1530.   /**************************************************************************
  1531.    * Find the instance data.                                                *
  1532.    **************************************************************************/
  1533.  
  1534.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1535.  
  1536.   /**************************************************************************
  1537.    * Invoke the About dialog.                                               *
  1538.    **************************************************************************/
  1539.  
  1540.    WinDlgBox ( HWND_DESKTOP, hwnd, PFNWP(AboutProcessor),
  1541.       Data->Library->QueryHandle(), IDD_ABOUT, 0 ) ;
  1542.  
  1543.   /**************************************************************************
  1544.    * Done.                                                                  *
  1545.    **************************************************************************/
  1546.  
  1547.    return ( MRFROMSHORT ( 0 ) ) ;
  1548. }
  1549.  
  1550. /****************************************************************************
  1551.  *                                                                          *
  1552.  *      Process Begin Drag message.                                         *
  1553.  *                                                                          *
  1554.  ****************************************************************************/
  1555.  
  1556. STATIC MRESULT APIENTRY BeginDrag ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1557.  
  1558.   /**************************************************************************
  1559.    * Determine the new window position.                                     *
  1560.    **************************************************************************/
  1561.  
  1562.    TRACKINFO TrackInfo ;
  1563.    memset ( &TrackInfo, 0, sizeof(TrackInfo) ) ;
  1564.  
  1565.    TrackInfo.cxBorder = 1 ;
  1566.    TrackInfo.cyBorder = 1 ;
  1567.    TrackInfo.cxGrid = 1 ;
  1568.    TrackInfo.cyGrid = 1 ;
  1569.    TrackInfo.cxKeyboard = 8 ;
  1570.    TrackInfo.cyKeyboard = 8 ;
  1571.  
  1572.    HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1573.  
  1574.    SWP Position ;
  1575.    WinQueryWindowPos ( Frame, &Position ) ;
  1576.    TrackInfo.rclTrack.xLeft   = Position.x ;
  1577.    TrackInfo.rclTrack.xRight  = Position.x + Position.cx ;
  1578.    TrackInfo.rclTrack.yBottom = Position.y ;
  1579.    TrackInfo.rclTrack.yTop    = Position.y + Position.cy ;
  1580.  
  1581.    WinQueryWindowPos ( HWND_DESKTOP, &Position ) ;
  1582.    TrackInfo.rclBoundary.xLeft   = Position.x ;
  1583.    TrackInfo.rclBoundary.xRight  = Position.x + Position.cx ;
  1584.    TrackInfo.rclBoundary.yBottom = Position.y ;
  1585.    TrackInfo.rclBoundary.yTop    = Position.y + Position.cy ;
  1586.  
  1587.    TrackInfo.ptlMinTrackSize.x = 0 ;
  1588.    TrackInfo.ptlMinTrackSize.y = 0 ;
  1589.    TrackInfo.ptlMaxTrackSize.x = Position.cx ;
  1590.    TrackInfo.ptlMaxTrackSize.y = Position.cy ;
  1591.  
  1592.    TrackInfo.fs = TF_MOVE | TF_STANDARD | TF_ALLINBOUNDARY ;
  1593.  
  1594.    if ( WinTrackRect ( HWND_DESKTOP, 0, &TrackInfo ) ) 
  1595.       WinSetWindowPos ( Frame, 0, TrackInfo.rclTrack.xLeft, TrackInfo.rclTrack.yBottom, 0, 0, SWP_MOVE ) ;
  1596.  
  1597.   /**************************************************************************
  1598.    * Done.                                                                  *
  1599.    **************************************************************************/
  1600.  
  1601.    return ( MRFROMSHORT ( 0 ) ) ;
  1602. }
  1603.  
  1604. /****************************************************************************
  1605.  *                                                                          *
  1606.  *      Process Mouse Button having been double-clicked.                    *
  1607.  *                                                                          *
  1608.  ****************************************************************************/
  1609.  
  1610. STATIC MRESULT APIENTRY ButtonDblClick ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1611.  
  1612.   /**************************************************************************
  1613.    * Send message to self to stop hiding the controls.                      *
  1614.    **************************************************************************/
  1615.  
  1616.    WinPostMsg ( hwnd, WM_COMMAND,
  1617.       MPFROM2SHORT ( IDM_HIDE_CONTROLS, 0 ),
  1618.       MPFROM2SHORT ( CMDSRC_OTHER, TRUE ) ) ;
  1619.  
  1620.   /**************************************************************************
  1621.    * We're done here.                                                       *
  1622.    **************************************************************************/
  1623.  
  1624.    return ( 0 ) ;
  1625. }
  1626.  
  1627. /****************************************************************************
  1628.  *                                                                          *
  1629.  *      Process Presentation Parameter Changed notification.                *
  1630.  *                                                                          *
  1631.  ****************************************************************************/
  1632.  
  1633. STATIC MRESULT APIENTRY ContextMenu ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1634.  
  1635.   /**************************************************************************
  1636.    * Find the instance data.                                                *
  1637.    **************************************************************************/
  1638.  
  1639.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1640.  
  1641.   /**************************************************************************
  1642.    * Invoke the window's context menu.                                      *
  1643.    **************************************************************************/
  1644.  
  1645.    WinSetPresParam ( Data->Menu, PP_FONTNAMESIZE, 0, PSZ("") ) ;
  1646.  
  1647.    WinPopupMenu ( hwnd, hwnd, Data->Menu, SHORT1FROMMP(mp1), SHORT2FROMMP(mp1),
  1648.       0, PU_HCONSTRAIN | PU_VCONSTRAIN | PU_KEYBOARD | PU_MOUSEBUTTON1 ) ;
  1649.  
  1650.   /**************************************************************************
  1651.    * Done.                                                                  *
  1652.    **************************************************************************/
  1653.  
  1654.    return ( MRESULT ( 0 ) ) ;
  1655. }
  1656.  
  1657. /****************************************************************************
  1658.  *                                                                          *
  1659.  *      Process Presentation Parameter Changed notification.                *
  1660.  *                                                                          *
  1661.  ****************************************************************************/
  1662.  
  1663. STATIC MRESULT APIENTRY PresParamChanged ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1664.  
  1665.  /***************************************************************************
  1666.   * Find the instance data.                                                 *
  1667.   ***************************************************************************/
  1668.  
  1669.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1670.  
  1671.  /***************************************************************************
  1672.   * Get the presentation parameter that changed.                            *
  1673.   ***************************************************************************/
  1674.  
  1675.   switch ( LONGFROMMP(mp1) )
  1676.   {
  1677.  
  1678.    /*************************************************************************
  1679.     * If font, note the fact that we now have a font to be saved as         *
  1680.     *   part of the configuration.  Get the font metrics and resize         *
  1681.     *   the window appropriately.                                           *
  1682.     *************************************************************************/
  1683.  
  1684.     case PP_FONTNAMESIZE:
  1685.     {
  1686.       ULONG ppid ;
  1687.       if ( WinQueryPresParam ( hwnd, PP_FONTNAMESIZE, 0, &ppid,
  1688.         sizeof(Data->IniData.FontNameSize), &Data->IniData.FontNameSize,
  1689.         0 ) )
  1690.       {
  1691.         Data->IniData.fFontNameSize = TRUE ;
  1692.       }
  1693.       else
  1694.       {
  1695.         strcpy ( PCHAR(Data->IniData.FontNameSize), "" ) ;
  1696.         Data->IniData.fFontNameSize = FALSE ;
  1697.         PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("FontNameSize"), NULL, 0 ) ;
  1698.       }
  1699.  
  1700.       HPS hPS = WinGetPS ( hwnd ) ;
  1701.       RECTL Rectangle ;
  1702.       WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  1703.       WinDrawText ( hPS, 1, PSZ(" "), &Rectangle, 0, 0, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  1704.       Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  1705.       Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  1706.       WinReleasePS ( hPS ) ;
  1707.       ResizeWindow ( hwnd ) ;
  1708.       break ;
  1709.     }
  1710.  
  1711.    /*************************************************************************
  1712.     * If background color, note the fact and repaint the window.            *
  1713.     *************************************************************************/
  1714.  
  1715.     case PP_BACKGROUNDCOLOR:
  1716.     {
  1717.       ULONG ppid ;
  1718.       if ( WinQueryPresParam ( hwnd, PP_BACKGROUNDCOLOR, 0, &ppid,
  1719.         sizeof(Data->IniData.BackColor), &Data->IniData.BackColor, 0 ) )
  1720.       {
  1721.         Data->IniData.fBackColor = TRUE ;
  1722.       }
  1723.       else
  1724.       {
  1725.         Data->IniData.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0 ) ;
  1726.         Data->IniData.fBackColor = FALSE ;
  1727.         PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("BackgroundColor"), NULL, 0 ) ;
  1728.       }
  1729.       WinInvalidateRect ( hwnd, 0, TRUE ) ;
  1730.       break ;
  1731.     }
  1732.  
  1733.    /*************************************************************************
  1734.     * If foreground color, note the fact and repaint the window.            *
  1735.     *************************************************************************/
  1736.  
  1737.     case PP_FOREGROUNDCOLOR:
  1738.     {
  1739.       ULONG ppid ;
  1740.       if ( WinQueryPresParam ( hwnd, PP_FOREGROUNDCOLOR, 0, &ppid,
  1741.         sizeof(Data->IniData.TextColor), &Data->IniData.TextColor, 0 ) )
  1742.       {
  1743.         Data->IniData.fTextColor = TRUE ;
  1744.       }
  1745.       else
  1746.       {
  1747.         Data->IniData.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0 ) ;
  1748.         Data->IniData.fTextColor = FALSE ;
  1749.         PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("ForegroundColor"), NULL, 0 ) ;
  1750.       }
  1751.       WinInvalidateRect ( hwnd, 0, TRUE ) ;
  1752.       break ;
  1753.     }
  1754.   }
  1755.  
  1756.  /***************************************************************************
  1757.   * Return through the default processor, letting window activation         *
  1758.   *   and other system functions occur.                                     *
  1759.   ***************************************************************************/
  1760.  
  1761.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1762. }
  1763.  
  1764. /****************************************************************************
  1765.  *                                                                          *
  1766.  *      Process System Color Change notification.                           *
  1767.  *                                                                          *
  1768.  ****************************************************************************/
  1769.  
  1770. STATIC MRESULT APIENTRY SysColorChange ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1771.  
  1772.  /***************************************************************************
  1773.   * Find the instance data.                                                 *
  1774.   ***************************************************************************/
  1775.  
  1776.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1777.  
  1778.  /***************************************************************************
  1779.   * If we aren't using custom colors, then query for the new defaults.      *
  1780.   ***************************************************************************/
  1781.  
  1782.   if ( NOT Data->IniData.fBackColor )
  1783.   {
  1784.     Data->IniData.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0 ) ;
  1785.   }
  1786.  
  1787.   if ( NOT Data->IniData.fTextColor )
  1788.   {
  1789.     Data->IniData.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0 ) ;
  1790.   }
  1791.  
  1792.  /***************************************************************************
  1793.   * Return value must be NULL, according to the documentation.              *
  1794.   ***************************************************************************/
  1795.  
  1796.   return ( MRFROMP ( NULL ) ) ;
  1797. }
  1798.  
  1799. /****************************************************************************
  1800.  *                                                                          *
  1801.  *      Process Query for Keys Help resource id.                            *
  1802.  *                                                                          *
  1803.  ****************************************************************************/
  1804.  
  1805. STATIC MRESULT APIENTRY QueryKeysHelp ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1806.  
  1807.  /***************************************************************************
  1808.   * Simply return the ID of the Keys Help panel.                            *
  1809.   ***************************************************************************/
  1810.  
  1811.   return ( (MRESULT) IDM_KEYS_HELP ) ;
  1812. }
  1813.  
  1814. /****************************************************************************
  1815.  *                                                                          *
  1816.  *      Process Help Manager Error                                          *
  1817.  *                                                                          *
  1818.  ****************************************************************************/
  1819.  
  1820. STATIC MRESULT APIENTRY HelpError ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1821.  
  1822.  /***************************************************************************
  1823.   * Local Declarations                                                      *
  1824.   ***************************************************************************/
  1825.  
  1826.   static struct
  1827.   {
  1828.     ULONG Error ;
  1829.     USHORT StringId ;
  1830.   }
  1831.   HelpErrors [] =
  1832.   {
  1833.     { HMERR_NO_FRAME_WND_IN_CHAIN,     IDS_HMERR_NO_FRAME_WND_IN_CHAIN },
  1834.     { HMERR_INVALID_ASSOC_APP_WND,     IDS_HMERR_INVALID_ASSOC_APP_WND },
  1835.     { HMERR_INVALID_ASSOC_HELP_INST,   IDS_HMERR_INVALID_ASSOC_HELP_IN },
  1836.     { HMERR_INVALID_DESTROY_HELP_INST, IDS_HMERR_INVALID_DESTROY_HELP_ },
  1837.     { HMERR_NO_HELP_INST_IN_CHAIN,     IDS_HMERR_NO_HELP_INST_IN_CHAIN },
  1838.     { HMERR_INVALID_HELP_INSTANCE_HDL, IDS_HMERR_INVALID_HELP_INSTANCE },
  1839.     { HMERR_INVALID_QUERY_APP_WND,     IDS_HMERR_INVALID_QUERY_APP_WND },
  1840.     { HMERR_HELP_INST_CALLED_INVALID,  IDS_HMERR_HELP_INST_CALLED_INVA },
  1841.     { HMERR_HELPTABLE_UNDEFINE,        IDS_HMERR_HELPTABLE_UNDEFINE    },
  1842.     { HMERR_HELP_INSTANCE_UNDEFINE,    IDS_HMERR_HELP_INSTANCE_UNDEFIN },
  1843.     { HMERR_HELPITEM_NOT_FOUND,        IDS_HMERR_HELPITEM_NOT_FOUND    },
  1844.     { HMERR_INVALID_HELPSUBITEM_SIZE,  IDS_HMERR_INVALID_HELPSUBITEM_S },
  1845.     { HMERR_HELPSUBITEM_NOT_FOUND,     IDS_HMERR_HELPSUBITEM_NOT_FOUND },
  1846.     { HMERR_INDEX_NOT_FOUND,           IDS_HMERR_INDEX_NOT_FOUND       },
  1847.     { HMERR_CONTENT_NOT_FOUND,         IDS_HMERR_CONTENT_NOT_FOUND     },
  1848.     { HMERR_OPEN_LIB_FILE,             IDS_HMERR_OPEN_LIB_FILE         },
  1849.     { HMERR_READ_LIB_FILE,             IDS_HMERR_READ_LIB_FILE         },
  1850.     { HMERR_CLOSE_LIB_FILE,            IDS_HMERR_CLOSE_LIB_FILE        },
  1851.     { HMERR_INVALID_LIB_FILE,          IDS_HMERR_INVALID_LIB_FILE      },
  1852.     { HMERR_NO_MEMORY,                 IDS_HMERR_NO_MEMORY             },
  1853.     { HMERR_ALLOCATE_SEGMENT,          IDS_HMERR_ALLOCATE_SEGMENT      },
  1854.     { HMERR_FREE_MEMORY,               IDS_HMERR_FREE_MEMORY           },
  1855.     { HMERR_PANEL_NOT_FOUND,           IDS_HMERR_PANEL_NOT_FOUND       },
  1856.     { HMERR_DATABASE_NOT_OPEN,         IDS_HMERR_DATABASE_NOT_OPEN     },
  1857.     { 0,                               IDS_HMERR_UNKNOWN               }
  1858.   } ;
  1859.  
  1860.   ULONG ErrorCode = (ULONG) LONGFROMMP ( mp1 ) ;
  1861.  
  1862.  /***************************************************************************
  1863.   * Find the instance data.                                                 *
  1864.   ***************************************************************************/
  1865.  
  1866.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1867.  
  1868.  /***************************************************************************
  1869.   * Find the error code in the message table.                               *
  1870.   ***************************************************************************/
  1871.  
  1872.   int Index = 0 ;
  1873.   while ( HelpErrors[Index].Error
  1874.     AND ( HelpErrors[Index].Error != ErrorCode ) )
  1875.   {
  1876.     Index ++ ;
  1877.   }
  1878.  
  1879.  /***************************************************************************
  1880.   * Get the message texts.                                                  *
  1881.   ***************************************************************************/
  1882.  
  1883.   ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1884.  
  1885.   ResourceString Message ( Data->Library->QueryHandle(), HelpErrors[Index].StringId ) ;
  1886.  
  1887.  /***************************************************************************
  1888.   * Display the error message.                                              *
  1889.   ***************************************************************************/
  1890.  
  1891.   WinMessageBox
  1892.   (
  1893.     HWND_DESKTOP,
  1894.     hwnd,
  1895.     PSZ(Message),
  1896.     PSZ(Title),
  1897.     0,
  1898.     MB_OK | MB_WARNING
  1899.   ) ;
  1900.  
  1901.  /***************************************************************************
  1902.   * Return zero, indicating that the message was processed.                 *
  1903.   ***************************************************************************/
  1904.  
  1905.   return ( MRFROMSHORT ( 0 ) ) ;
  1906. }
  1907.  
  1908. /****************************************************************************
  1909.  *                                                                          *
  1910.  *      Process "Extended Help Undefined" notification                      *
  1911.  *                                                                          *
  1912.  ****************************************************************************/
  1913.  
  1914. STATIC MRESULT APIENTRY ExtHelpUndefined ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1915.  
  1916.  /***************************************************************************
  1917.   * Find the instance data.                                                 *
  1918.   ***************************************************************************/
  1919.  
  1920.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1921.  
  1922.  /***************************************************************************
  1923.   * Get the message texts.                                                  *
  1924.   ***************************************************************************/
  1925.  
  1926.   ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1927.  
  1928.   ResourceString Message ( Data->Library->QueryHandle(), IDS_HMERR_EXTHELPUNDEFINED ) ;
  1929.  
  1930.  /***************************************************************************
  1931.   * Display the error message.                                              *
  1932.   ***************************************************************************/
  1933.  
  1934.   WinMessageBox
  1935.   (
  1936.     HWND_DESKTOP,
  1937.     hwnd,
  1938.     PSZ(Message),
  1939.     PSZ(Title),
  1940.     0,
  1941.     MB_OK | MB_WARNING
  1942.   ) ;
  1943.  
  1944.  /***************************************************************************
  1945.   * Return zero, indicating that the message was processed.                 *
  1946.   ***************************************************************************/
  1947.  
  1948.   return ( MRFROMSHORT ( 0 ) ) ;
  1949. }
  1950.  
  1951. /****************************************************************************
  1952.  *                                                                          *
  1953.  *      Process "Help Subitem Not Found" notification                       *
  1954.  *                                                                          *
  1955.  ****************************************************************************/
  1956.  
  1957. STATIC MRESULT APIENTRY HelpSubitemNotFound ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1958.  
  1959.  /***************************************************************************
  1960.   * Find the instance data.                                                 *
  1961.   ***************************************************************************/
  1962.  
  1963.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1964.  
  1965.  /***************************************************************************
  1966.   * Get the title text.                                                     *
  1967.   ***************************************************************************/
  1968.  
  1969.   ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1970.  
  1971.  /***************************************************************************
  1972.   * Format the error message.                                               *
  1973.   ***************************************************************************/
  1974.  
  1975.   USHORT Topic = (USHORT) SHORT1FROMMP ( mp2 ) ;
  1976.   USHORT Subtopic = (USHORT) SHORT2FROMMP ( mp2 ) ;
  1977.  
  1978.   ResourceString Frame   ( Data->Library->QueryHandle(), IDS_HELPMODE_FRAME ) ;
  1979.   ResourceString Menu    ( Data->Library->QueryHandle(), IDS_HELPMODE_MENU ) ;
  1980.   ResourceString Window  ( Data->Library->QueryHandle(), IDS_HELPMODE_WINDOW ) ;
  1981.   ResourceString Unknown ( Data->Library->QueryHandle(), IDS_HELPMODE_UNKNOWN ) ;
  1982.  
  1983.   PBYTE Mode ;
  1984.   switch ( SHORT1FROMMP ( mp1 ) )
  1985.   {
  1986.     case HLPM_FRAME:
  1987.       Mode = PSZ(Frame) ;
  1988.       break ;
  1989.  
  1990.     case HLPM_MENU:
  1991.       Mode = PSZ(Menu) ;
  1992.       break ;
  1993.  
  1994.     case HLPM_WINDOW:
  1995.       Mode = PSZ(Window) ;
  1996.       break ;
  1997.  
  1998.     default:
  1999.       Mode = PSZ(Unknown) ;
  2000.   }
  2001.  
  2002.   ResourceString Format ( Data->Library->QueryHandle(), IDS_HELPSUBITEMNOTFOUND ) ;
  2003.  
  2004.   BYTE Message [200] ;
  2005.   sprintf ( PCHAR(Message), PCHAR(Format), Mode, Topic, Subtopic ) ;
  2006.  
  2007.  /***************************************************************************
  2008.   * Display the error message.                                              *
  2009.   ***************************************************************************/
  2010.  
  2011.   WinMessageBox
  2012.   (
  2013.     HWND_DESKTOP,
  2014.     hwnd,
  2015.     Message,
  2016.     PSZ(Title),
  2017.     0,
  2018.     MB_OK | MB_WARNING
  2019.   ) ;
  2020.  
  2021.  /***************************************************************************
  2022.   * Return zero, indicating that the message was processed.                 *
  2023.   ***************************************************************************/
  2024.  
  2025.   return ( MRFROMSHORT ( 0 ) ) ;
  2026. }
  2027.  
  2028. /****************************************************************************
  2029.  *                                                                          *
  2030.  *      Process Refresh message.                                            *
  2031.  *                                                                          *
  2032.  ****************************************************************************/
  2033.  
  2034. STATIC MRESULT APIENTRY Refresh ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  2035.  
  2036.  /***************************************************************************
  2037.   * Find the instance data.                                                 *
  2038.   ***************************************************************************/
  2039.  
  2040.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  2041.  
  2042.  /***************************************************************************
  2043.   * If we're supposed to float the window, do so here.                      *
  2044.   ***************************************************************************/
  2045.  
  2046.   if ( Data->IniData.Float )
  2047.     WinSetWindowPos ( WinQueryWindow(hwnd,QW_PARENT), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER ) ;
  2048.  
  2049.  /***************************************************************************
  2050.   * Save the idle counter.                                                  *
  2051.   ***************************************************************************/
  2052.  
  2053.   Data->IniData.IdleCount = LONGFROMMP ( mp1 ) ;
  2054.  
  2055.  /***************************************************************************
  2056.   * Determine if drive mask has changed.                                    *
  2057.   ***************************************************************************/
  2058.  
  2059.   ULONG Drive ;
  2060.   ULONG Drives ;
  2061.   DosQueryCurrentDisk ( &Drive, &Drives ) ;
  2062.  
  2063.   if ( Drives != Data->Drives ) {
  2064.  
  2065.    /*************************************************************************
  2066.     * It has.  First save the display options.                              *
  2067.     *************************************************************************/
  2068.  
  2069.     SaveApplication ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ;
  2070.  
  2071.    /*************************************************************************
  2072.     * Next, update the drive item list.                                     *
  2073.     *************************************************************************/
  2074.  
  2075.     UpdateDriveList ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), Data->IniFile->QueryHandle(),
  2076.       &Data->IniData, Data->pDdeServer, Data->Drives, Drives ) ;
  2077.  
  2078.    /*************************************************************************
  2079.     * Save the updated drive mask.                                          *
  2080.     *************************************************************************/
  2081.  
  2082.     Data->Drives = Drives ;
  2083.  
  2084.    /*************************************************************************
  2085.     * Resize the window to accommodate the new option list.                 *
  2086.     *************************************************************************/
  2087.  
  2088.     ResizeWindow ( hwnd ) ;
  2089.   }
  2090.  
  2091.  /***************************************************************************
  2092.   * Update the statistics.                                                  *
  2093.   ***************************************************************************/
  2094.  
  2095.   UpdateWindow ( hwnd, Data, FALSE ) ;
  2096.  
  2097.  /***************************************************************************
  2098.   * Return zero, indicating that the message was processed.                 *
  2099.   ***************************************************************************/
  2100.  
  2101.   return ( MRFROMSHORT ( 0 ) ) ;
  2102. }
  2103.  
  2104.  
  2105. /****************************************************************************
  2106.  *                                                                          *
  2107.  *      Process DDE Initiate request                                        *
  2108.  *                                                                          *
  2109.  ****************************************************************************/
  2110.  
  2111. STATIC MRESULT APIENTRY Dde_Initiate ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  2112.  
  2113.  /***************************************************************************
  2114.   * Find the instance data.                                                 *
  2115.   ***************************************************************************/
  2116.  
  2117.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  2118.  
  2119.  /***************************************************************************
  2120.   * Pass the request to the DDE Server.                                     *
  2121.   ***************************************************************************/
  2122.  
  2123.   Data->pDdeServer->Initiate ( hwnd, HWNDFROMMP(mp1), PDDEINIT(PVOIDFROMMP(mp2)) ) ;
  2124.  
  2125.  /***************************************************************************
  2126.   * Return zero, indicating that the message was processed.                 *
  2127.   ***************************************************************************/
  2128.  
  2129.   return ( MRFROMSHORT ( 0 ) ) ;
  2130. }
  2131.  
  2132.  
  2133. /****************************************************************************
  2134.  *                                                                          *
  2135.  *                      Get Expanded INI Information                        *
  2136.  *                                                                          *
  2137.  ****************************************************************************/
  2138.  
  2139. STATIC int GetIniData ( HAB Anchor, HMODULE Library, HINI IniHandle, PINIDATA IniData, Dde_Server *pDdeServer ) {
  2140.  
  2141.  /***************************************************************************
  2142.   * Get the basic INI information.                                          *
  2143.   ***************************************************************************/
  2144.  
  2145.   if ( GetIniData ( IniHandle, IniData ) )
  2146.      return ( 1 ) ;
  2147.  
  2148.  /***************************************************************************
  2149.   * Initialize the global resource strings.                                 *
  2150.   ***************************************************************************/
  2151.  
  2152.   IniData->Day        = new ResourceString ( Library, IDS_DAY ) ;
  2153.   IniData->Days       = new ResourceString ( Library, IDS_DAYS ) ;
  2154.   IniData->DaysOfWeek = new ResourceString ( Library, IDS_DAYSOFWEEK ) ;
  2155.   IniData->DriveError = new ResourceString ( Library, IDS_DRIVEERROR ) ;
  2156.  
  2157.  /***************************************************************************
  2158.   * Get country information.                                                *
  2159.   ***************************************************************************/
  2160.  
  2161.   COUNTRYCODE CountryCode ;
  2162.   ULONG Count ;
  2163.   ULONG Status ;
  2164.  
  2165.   CountryCode.country = 0 ;
  2166.   CountryCode.codepage = 0 ;
  2167.  
  2168.   Status = DosGetCtryInfo ( sizeof(IniData->CountryInfo), &CountryCode,
  2169.     &IniData->CountryInfo, &Count ) ;
  2170.   if ( Status ) {
  2171.     IniData->CountryInfo.fsDateFmt = DATEFMT_MM_DD_YY ;
  2172.     IniData->CountryInfo.fsTimeFmt = 0 ;
  2173.     IniData->CountryInfo.szDateSeparator[0] = '/' ;
  2174.     IniData->CountryInfo.szDateSeparator[1] = 0 ;
  2175.     IniData->CountryInfo.szTimeSeparator[0] = ':' ;
  2176.     IniData->CountryInfo.szTimeSeparator[1] = 0 ;
  2177.     IniData->CountryInfo.szThousandsSeparator[0] = ',' ;
  2178.     IniData->CountryInfo.szThousandsSeparator[1] = 0 ;
  2179.   }
  2180.  
  2181.   char Text [10] ;
  2182.   ULONG Size = 10 ;
  2183.   if ( PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("iDate"), Text, &Size ) )
  2184.      IniData->CountryInfo.fsDateFmt = atoi ( Text ) ;
  2185.  
  2186.   Size = 10 ;
  2187.   if ( PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("iTime"), Text, &Size ) )
  2188.      IniData->CountryInfo.fsTimeFmt = UCHAR ( atoi ( Text ) ) ;
  2189.  
  2190.   Size = 10 ;
  2191.   if ( PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("iCountry"), Text, &Size ) )
  2192.      IniData->idCountry = atoi ( Text ) ;
  2193.  
  2194.   Size = 2 ;
  2195.   PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("sDate"), IniData->CountryInfo.szDateSeparator, &Size ) ;
  2196.  
  2197.   Size = 2 ;
  2198.   PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("sTime"), IniData->CountryInfo.szTimeSeparator, &Size ) ;
  2199.  
  2200.   Size = 8 ;
  2201.   strcpy ( IniData->szAm, "am" ) ;
  2202.   PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("s1159"), IniData->szAm, &Size ) ;
  2203.  
  2204.   Size = 8 ;
  2205.   strcpy ( IniData->szPm, "pm" ) ;
  2206.   PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("s2359"), IniData->szPm, &Size ) ;
  2207.  
  2208.   Size = 2 ;
  2209.   PrfQueryProfileData ( HINI_USERPROFILE, PSZ("PM_National"), PSZ("sThousand"), IniData->CountryInfo.szThousandsSeparator, &Size ) ;
  2210.  
  2211.  /***************************************************************************
  2212.   * Get the SWAPPATH statement from CONFIG.SYS.                             *
  2213.   ***************************************************************************/
  2214.  
  2215.   PSZ Swappath = ScanSystemConfig ( Anchor, PSZ("SWAPPATH") ) ;
  2216.  
  2217.   if ( Swappath == NULL )
  2218.     Swappath = PSZ("C:\\OS2\\SYSTEM 0") ;
  2219.  
  2220.   char *p = CopyString ( PCHAR(IniData->SwapPath), PCHAR(Swappath) ) ;
  2221.   sscanf ( p, " %li", &IniData->MinFree ) ;
  2222.  
  2223.  /***************************************************************************
  2224.   * Find out where the spool work directory is.                             *
  2225.   ***************************************************************************/
  2226.  
  2227.   IniData->SpoolPath = 0 ;
  2228.  
  2229.   if ( PrfQueryProfileSize ( HINI_PROFILE, PSZ("PM_SPOOLER"), PSZ("DIR"), &Size ) ) {
  2230.     IniData->SpoolPath = PSZ ( malloc ( (int)Size ) ) ;
  2231.     if ( IniData->SpoolPath ) {
  2232.       if ( PrfQueryProfileData ( HINI_PROFILE, PSZ("PM_SPOOLER"), PSZ("DIR"), IniData->SpoolPath, &Size ) ) {
  2233.         PBYTE p = PBYTE( strchr ( PCHAR(IniData->SpoolPath), ';' ) ) ;
  2234.         if ( p ) {
  2235.           *p = 0 ;
  2236.         }
  2237.       } else {
  2238.         free ( IniData->SpoolPath ) ;
  2239.         IniData->SpoolPath = 0 ;
  2240.       }
  2241.     }
  2242.   }
  2243.  
  2244.   if ( IniData->SpoolPath == 0 )
  2245.      IniData->SpoolPath = PSZ ( "C:\\SPOOL" ) ;
  2246.  
  2247.  /***************************************************************************
  2248.   * Build the fixed portion of the item list.                               *
  2249.   ***************************************************************************/
  2250.  
  2251.   ResourceString ClockLabel ( Library, IDS_CLOCK ) ;
  2252.   IniData->Items[ITEM_CLOCK].pItem = new Clock ( ITEM_CLOCK,
  2253.     "ShowClock", ClockLabel, ClockLabel, pDdeServer, "Items",
  2254.     IniData->CountryInfo, IniData->szAm, IniData->szPm,
  2255.     IniData->DaysOfWeek, IniData->ShowSeconds ) ;
  2256.  
  2257.   ResourceString ElapsedLabel ( Library, IDS_ELAPSED ) ;
  2258.   IniData->Items[ITEM_ELAPSEDTIME].pItem = new ElapsedTime ( ITEM_ELAPSEDTIME,
  2259.     "ShowElapsed", ElapsedLabel, ElapsedLabel, pDdeServer, "Items",
  2260.     IniData->CountryInfo, IniData->Day,
  2261.     IniData->Days, IniData->ShowSeconds ) ;
  2262.  
  2263.   ResourceString MemoryLabel ( Library, IDS_MEMORY ) ;
  2264.   IniData->Items[ITEM_MEMORYFREE].pItem = new MemoryFree ( ITEM_MEMORYFREE,
  2265.     "ShowMemory", MemoryLabel, MemoryLabel, pDdeServer, "Items",
  2266.     IniData->CountryInfo, IniData->ShowK ) ;
  2267.  
  2268.   ResourceString VirtualLabel ( Library, IDS_VIRTUAL ) ;
  2269.   IniData->Items[ITEM_VIRTUALFREE].pItem = new VirtualFree ( ITEM_VIRTUALFREE,
  2270.     "ShowVirtual", VirtualLabel, VirtualLabel, pDdeServer, "Items",
  2271.     IniData->CountryInfo, IniData->ShowK ) ;
  2272.  
  2273.   ResourceString SwapSizeLabel ( Library, IDS_SWAPSIZE ) ;
  2274.   IniData->Items[ITEM_SWAPFILESIZE].pItem = new SwapSize ( ITEM_SWAPFILESIZE,
  2275.     "ShowSwapsize", SwapSizeLabel, SwapSizeLabel, pDdeServer, "Items",
  2276.     IniData->CountryInfo, IniData->ShowK, IniData->SwapPath ) ;
  2277.  
  2278.   ResourceString SwapFreeLabel ( Library, IDS_SWAPFREE ) ;
  2279.   IniData->Items[ITEM_SWAPDISKFREE].pItem = new SwapFree ( ITEM_SWAPDISKFREE,
  2280.     "ShowSwapfree", SwapFreeLabel, SwapFreeLabel, pDdeServer, "Items",
  2281.     IniData->CountryInfo, IniData->ShowK, IniData->SwapPath, IniData->MinFree ) ;
  2282.  
  2283.   ResourceString SwapSlackLabel ( Library, IDS_SWAPSLACK ) ;
  2284.   IniData->Items[ITEM_SWAPFILESLACK].pItem = new SwapSlack ( ITEM_SWAPFILESLACK,
  2285.     "ShowSwapSlack", SwapSlackLabel, SwapSlackLabel, pDdeServer, "Items",
  2286.     IniData->CountryInfo, IniData->ShowK,
  2287.     (VirtualFree*)IniData->Items[ITEM_VIRTUALFREE].pItem,
  2288.     (SwapFree*)IniData->Items[ITEM_SWAPDISKFREE].pItem,
  2289.     (MemoryFree*)IniData->Items[ITEM_MEMORYFREE].pItem ) ;
  2290.  
  2291.   ResourceString SpoolSizeLabel ( Library, IDS_SPOOLSIZE ) ;
  2292.   IniData->Items[ITEM_SPOOLFILESIZE].pItem = new SpoolSize ( ITEM_SPOOLFILESIZE,
  2293.     "ShowSpoolSize", SpoolSizeLabel, SpoolSizeLabel, pDdeServer, "Items",
  2294.     IniData->CountryInfo, IniData->ShowK, IniData->SpoolPath ) ;
  2295.  
  2296.   ResourceString CpuLoadLabel ( Library, IDS_CPULOAD ) ;
  2297.   IniData->Items[ITEM_CPULOAD].pItem = new CpuLoad ( ITEM_CPULOAD,
  2298.     "ShowCpuLoad", CpuLoadLabel, CpuLoadLabel, pDdeServer, "Items",
  2299.     IniData->MaxCount, &IniData->IdleCount ) ;
  2300.  
  2301.   ResourceString TaskCountLabel ( Library, IDS_TASKCOUNT ) ;
  2302.   IniData->Items[ITEM_TASKCOUNT].pItem = new TaskCount ( ITEM_TASKCOUNT,
  2303.     "ShowTaskCount", TaskCountLabel, TaskCountLabel, pDdeServer, "Items",
  2304.     Anchor ) ;
  2305.  
  2306.   ResourceString ProcessCountLabel ( Library, IDS_PROCESSCOUNT ) ;
  2307.   IniData->Items[ITEM_PROCESSCOUNT].pItem = new ProcessCount ( ITEM_PROCESSCOUNT,
  2308.     "ShowProcessCount", ProcessCountLabel, ProcessCountLabel, pDdeServer, "Items" ) ;
  2309.  
  2310.   ResourceString ThreadCountLabel ( Library, IDS_THREADCOUNT ) ;
  2311.   IniData->Items[ITEM_THREADCOUNT].pItem = new ThreadCount ( ITEM_THREADCOUNT,
  2312.     "ShowThreadCount", ThreadCountLabel, ThreadCountLabel, pDdeServer, "Items" ) ;
  2313.  
  2314.   ResourceString TotalFreeLabel ( Library, IDS_TOTALFREE ) ;
  2315.   IniData->Items[ITEM_TOTALFREE].pItem = new TotalFree ( ITEM_TOTALFREE,
  2316.     "ShowTotalFree", TotalFreeLabel, TotalFreeLabel, pDdeServer, "Items",
  2317.     IniData->CountryInfo, IniData->ShowK, 0 ) ;
  2318.  
  2319.   for ( int i=0; i<ITEM_BASE_COUNT; i++ ) {
  2320.  
  2321.      Item *pItem = IniData->Items[i].pItem ;
  2322.  
  2323.      BOOL Flag = TRUE ;
  2324.      if ( PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ(pItem->QueryName()), &Size )
  2325.         AND ( ( Size == sizeof(Flag) ) OR ( Size == sizeof(short) ) )
  2326.         AND PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ(pItem->QueryName()), &Flag, &Size ) ) {
  2327.  
  2328.      } /* endif */
  2329.  
  2330.      if ( Flag )
  2331.         IniData->Items[i].pItem->SetFlag() ;
  2332.      else
  2333.         IniData->Items[i].pItem->ResetFlag() ;
  2334.  
  2335.      char Tag [80] ;
  2336.      strcpy ( Tag, PCHAR(IniData->Items[i].pItem->QueryName()) ) ;
  2337.      strcat ( Tag, " Label" ) ;
  2338.      IniData->Items[i].fLabel = FALSE ;
  2339.      if ( PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ(Tag), &Size )
  2340.         AND ( Size == sizeof(IniData->Items[i].Label) )
  2341.         AND PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ(Tag), &IniData->Items[i].Label, &Size )
  2342.         AND IniData->Items[i].Label[0] ) {
  2343.  
  2344.         IniData->Items[i].fLabel = TRUE ;
  2345.         IniData->Items[i].pItem->SetLabel ( IniData->Items[i].Label ) ;
  2346.  
  2347.      } /* endif */
  2348.  
  2349.   } /* endfor */
  2350.  
  2351.  /***************************************************************************
  2352.   * Add items for each drive on the system.                                 *
  2353.   ***************************************************************************/
  2354.  
  2355.   ULONG Drive, Drives ;
  2356.   DosQueryCurrentDisk ( &Drive, &Drives ) ;
  2357.   UpdateDriveList ( Anchor, Library, IniHandle, IniData, pDdeServer, 0, Drives ) ;
  2358.  
  2359.   return ( 0 ) ;
  2360. }
  2361.  
  2362. /****************************************************************************
  2363.  *                                                                          *
  2364.  *      Scan CONFIG.SYS for a keyword.  Return the value.                   *
  2365.  *                                                                          *
  2366.  ****************************************************************************/
  2367.  
  2368. STATIC PSZ ScanSystemConfig ( HAB Anchor, PSZ Keyword ) {
  2369.  
  2370.  /***************************************************************************
  2371.   * Get the boot drive number from the global information segment.          *
  2372.   ***************************************************************************/
  2373.  
  2374.   ULONG BootDrive ;
  2375.   DosQuerySysInfo ( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &BootDrive, sizeof(BootDrive) ) ;
  2376.  
  2377.  /***************************************************************************
  2378.   * Convert the keyword to upper case.                                      *
  2379.   ***************************************************************************/
  2380.  
  2381.   WinUpper ( Anchor, 0, 0, Keyword ) ;
  2382.  
  2383.  /***************************************************************************
  2384.   * Build the CONFIG.SYS path.                                              *
  2385.   ***************************************************************************/
  2386.  
  2387.   char Path [_MAX_PATH] ;
  2388.   Path[0] = (char) ( BootDrive + 'A' - 1 ) ;
  2389.   Path[1] = 0 ;
  2390.   strcat ( Path, ":\\CONFIG.SYS" ) ;
  2391.  
  2392.  /***************************************************************************
  2393.   * Open CONFIG.SYS for reading.                                            *
  2394.   ***************************************************************************/
  2395.  
  2396.   FILE *File = fopen ( Path, "r" ) ;
  2397.   if ( NOT File )
  2398.     return ( 0 ) ;
  2399.  
  2400.  /***************************************************************************
  2401.   * While there're more lines in CONFIG.SYS, read a line and check it.      *
  2402.   ***************************************************************************/
  2403.  
  2404.   static char Buffer [500] ;
  2405.   while ( fgets ( Buffer, sizeof(Buffer), File ) ) {
  2406.  
  2407.    /*************************************************************************
  2408.     * Clean any trailing newline character from the input string.           *
  2409.     *************************************************************************/
  2410.  
  2411.     if ( Buffer[strlen(Buffer)-1] == '\n' )
  2412.       Buffer[strlen(Buffer)-1] = 0 ;
  2413.  
  2414.    /*************************************************************************
  2415.     * If keyword starts the line, we've found the line we want.  Close      *
  2416.     *   the file and return a pointer to the parameter text.                *
  2417.     *************************************************************************/
  2418.  
  2419.     WinUpper ( Anchor, 0, 0, PSZ(Buffer) ) ;
  2420.  
  2421.     char *p = Buffer ;
  2422.     while ( *p AND ( ( *p == ' ' ) OR ( *p == '\t' ) ) ) p++ ;
  2423.  
  2424.     if ( strncmp ( p, PCHAR(Keyword), strlen(PCHAR(Keyword)) ) )
  2425.        continue ;
  2426.  
  2427.     p += strlen(PCHAR(Keyword)) ;
  2428.     while ( *p AND ( ( *p == ' ' ) OR ( *p == '\t' ) ) ) p++ ;
  2429.  
  2430.     if ( *p++ != '=' )
  2431.        continue ;
  2432.  
  2433.     while ( *p AND ( ( *p == ' ' ) OR ( *p == '\t' ) ) ) p++ ;
  2434.  
  2435.     fclose ( File ) ;
  2436.     return ( PSZ(p) ) ;
  2437.  
  2438.   }
  2439.  
  2440.  /***************************************************************************
  2441.   * Close the file.  We haven't found the line we wanted.                   *
  2442.   ***************************************************************************/
  2443.  
  2444.   fclose ( File ) ;
  2445.  
  2446.   return ( 0 ) ;
  2447. }
  2448.  
  2449. /****************************************************************************
  2450.  *                                                                          *
  2451.  *                          Copy Quoted String                              *
  2452.  *                                                                          *
  2453.  ****************************************************************************/
  2454.  
  2455. STATIC char *CopyString ( char *Buffer, char *Original ) {
  2456.    char *p1 = PCHAR(Original), *p2 = Buffer ;
  2457.    BOOL Quoted = FALSE ;
  2458.    *p2 = 0 ;
  2459.    while ( *p1 ) {
  2460.       if ( Quoted ) {
  2461.          if ( *p1 == '"' ) {
  2462.             Quoted = FALSE ;
  2463.          } else {
  2464.             *p2++ = *p1 ;
  2465.             *p2 = 0 ;
  2466.          } /* endif */
  2467.       } else {
  2468.          if ( *p1 == '"' ) {
  2469.             Quoted = TRUE ;
  2470.          } else if ( ( *p1 == ' ' ) OR ( *p1 == '\t' ) ) {
  2471.             break ;
  2472.          } else {
  2473.             *p2++ = *p1 ;
  2474.             *p2 = 0 ;
  2475.          } /* endif */
  2476.       } /* endif */
  2477.       p1 ++ ;
  2478.    } /* endwhile */
  2479.    return ( p1 ) ;
  2480. }
  2481.  
  2482. /****************************************************************************
  2483.  *                                                                          *
  2484.  *                       Resize Client Window                               *
  2485.  *                                                                          *
  2486.  ****************************************************************************/
  2487.  
  2488. STATIC void ResizeWindow ( HWND hwnd ) {
  2489.  
  2490.   /**************************************************************************
  2491.    * Find the instance data.                                                *
  2492.    **************************************************************************/
  2493.  
  2494.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  2495.  
  2496.   /**************************************************************************
  2497.    * Determine how many items are to be displayed.                          *
  2498.    **************************************************************************/
  2499.  
  2500.    HPS hPS = WinGetPS ( hwnd ) ;
  2501.    GpiSetCp ( hPS, Data->CodePage ) ;
  2502.  
  2503.    int Count = 0 ;
  2504.    LONG Widest = 0 ;
  2505.    LONG Height = 0 ;
  2506.    Data->MaxColumns = 0 ;
  2507.  
  2508.    for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  2509.       Item *pItem = Data->IniData.Items[i].pItem ;
  2510.       if ( pItem->QueryFlag() ) {
  2511.          Count ++ ;
  2512.          RECTL Rectangle ;
  2513.          int Columns = pItem->Measure ( hPS, Rectangle ) ;
  2514.          Widest = max ( Widest, (Rectangle.xRight-Rectangle.xLeft+1) ) ;
  2515.          Height += Rectangle.yTop - Rectangle.yBottom ;
  2516.          Data->MaxColumns = max ( Data->MaxColumns, Columns ) ;
  2517.       } /* endif */
  2518.    } /* endfor */
  2519.  
  2520.    WinReleasePS ( hPS ) ;
  2521.  
  2522.   /**************************************************************************
  2523.    * If the window is visible and minimized, restore it invisibly.          *
  2524.    **************************************************************************/
  2525.  
  2526.    HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  2527.  
  2528.    BOOL fHadToHide = FALSE ;
  2529.    BOOL fHadToRestore = FALSE ;
  2530.    if ( Data->IniData.Position.fl & SWP_MINIMIZE ) {
  2531.       if ( WinIsWindowVisible ( Frame ) ) {
  2532.          WinShowWindow ( Frame, FALSE ) ;
  2533.          fHadToHide = TRUE ;
  2534.       } /* endif */
  2535.       WinSetWindowPos ( Frame, 0, 0, 0, 0, 0, SWP_RESTORE ) ;
  2536.       fHadToRestore = TRUE ;
  2537.    } /* endif */
  2538.  
  2539.   /**************************************************************************
  2540.    * Get the entire window's current size and position.                     *
  2541.    **************************************************************************/
  2542.  
  2543.    SWP Position ;
  2544.    WinQueryWindowPos ( Frame, &Position ) ;
  2545.  
  2546.    RECTL Rectangle = { Position.x, Position.y, Position.x+Position.cx, Position.y+Position.cy } ;
  2547.  
  2548.    WinCalcFrameRect ( Frame, &Rectangle, TRUE ) ;
  2549.  
  2550.   /**************************************************************************
  2551.    * Determine the anchor point.                                            *
  2552.    **************************************************************************/
  2553.  
  2554.    POINTL Anchor ;
  2555.    switch ( Data->IniData.AnchorCorner ) {
  2556.       case CORNER_BL:
  2557.       default:
  2558.          Anchor.x = Rectangle.xLeft ;
  2559.          Anchor.y = Rectangle.yBottom ;
  2560.          break;
  2561.       case CORNER_BR:
  2562.          Anchor.x = Rectangle.xRight ;
  2563.          Anchor.y = Rectangle.yBottom ;
  2564.          break;
  2565.       case CORNER_TL:
  2566.          Anchor.x = Rectangle.xLeft ;
  2567.          Anchor.y = Rectangle.yTop ;
  2568.          break;
  2569.       case CORNER_TR:
  2570.          Anchor.x = Rectangle.xRight ;
  2571.          Anchor.y = Rectangle.yTop ;
  2572.          break;
  2573.    } /* endswitch */
  2574.  
  2575.   /**************************************************************************
  2576.    * Determine the new window size (with frame).                            *
  2577.    **************************************************************************/
  2578.  
  2579.    Rectangle.xLeft = Rectangle.yBottom = 0 ;
  2580.    Rectangle.xRight = Widest ;
  2581.    Rectangle.yTop = Height ;
  2582.  
  2583.   /**************************************************************************
  2584.    * Determine the new rectangle.                                           *
  2585.    **************************************************************************/
  2586.  
  2587.    switch ( Data->IniData.AnchorCorner ) {
  2588.       case CORNER_BL:
  2589.       default:
  2590.          Rectangle.xRight = Anchor.x + ( Rectangle.xRight - Rectangle.xLeft ) ;
  2591.          Rectangle.xLeft = Anchor.x ;
  2592.          Rectangle.yTop = Anchor.y + ( Rectangle.yTop - Rectangle.yBottom ) ;
  2593.          Rectangle.yBottom = Anchor.y ;
  2594.          break;
  2595.       case CORNER_BR:
  2596.          Rectangle.xLeft = Anchor.x - ( Rectangle.xRight - Rectangle.xLeft ) ;
  2597.          Rectangle.xRight = Anchor.x ;
  2598.          Rectangle.yTop = Anchor.y + ( Rectangle.yTop - Rectangle.yBottom ) ;
  2599.          Rectangle.yBottom = Anchor.y ;
  2600.          break;
  2601.       case CORNER_TL:
  2602.          Rectangle.xRight = Anchor.x + ( Rectangle.xRight - Rectangle.xLeft ) ;
  2603.          Rectangle.xLeft = Anchor.x ;
  2604.          Rectangle.yBottom = Anchor.y - ( Rectangle.yTop - Rectangle.yBottom ) ;
  2605.          Rectangle.yTop = Anchor.y ;
  2606.          break;
  2607.       case CORNER_TR:
  2608.          Rectangle.xLeft = Anchor.x - ( Rectangle.xRight - Rectangle.xLeft ) ;
  2609.          Rectangle.xRight = Anchor.x ;
  2610.          Rectangle.yBottom = Anchor.y - ( Rectangle.yTop - Rectangle.yBottom ) ;
  2611.          Rectangle.yTop = Anchor.y ;
  2612.          break;
  2613.    } /* endswitch */
  2614.  
  2615.    WinCalcFrameRect ( Frame, &Rectangle, FALSE ) ;
  2616.  
  2617.   /**************************************************************************
  2618.    * Move and size the window.                                              *
  2619.    **************************************************************************/
  2620.  
  2621.    #ifdef DEBUG
  2622.    Log ( "Resize: Setting window position to %i,%i (%ix%i).",
  2623.       Rectangle.xLeft, Rectangle.yBottom,
  2624.       Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom ) ;
  2625.    #endif
  2626.  
  2627.    WinSetWindowPos ( Frame, 0, Rectangle.xLeft, Rectangle.yBottom,
  2628.       Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom,
  2629.       SWP_MOVE | SWP_SIZE ) ;
  2630.  
  2631.   /**************************************************************************
  2632.    * Return the window to its original state.                               *
  2633.    **************************************************************************/
  2634.  
  2635.    if ( fHadToRestore ) {
  2636.       #ifdef DEBUG
  2637.       Log ( "Resize: Restoring window position to %i,%i (%ix%i).",
  2638.          Data->IniData.Position.x, Data->IniData.Position.y,
  2639.          Data->IniData.Position.cx, Data->IniData.Position.cy ) ;
  2640.       #endif
  2641.       WinSetWindowPos ( Frame, 0,
  2642.          Data->IniData.Position.x, Data->IniData.Position.y,
  2643.          Data->IniData.Position.cx, Data->IniData.Position.cy,
  2644.          SWP_MOVE | SWP_SIZE | SWP_MINIMIZE ) ;
  2645.    } /* endif */
  2646.  
  2647.    if ( fHadToHide )
  2648.       WinShowWindow ( Frame, TRUE ) ;
  2649.  
  2650.   /**************************************************************************
  2651.    * Invalidate the window so that it gets repainted.                       *
  2652.    **************************************************************************/
  2653.  
  2654.    WinInvalidateRect ( hwnd, 0, TRUE ) ;
  2655. }
  2656.  
  2657. /****************************************************************************
  2658.  *                                                                          *
  2659.  *                      Hide Window Controls                                *
  2660.  *                                                                          *
  2661.  ****************************************************************************/
  2662.  
  2663. STATIC void HideControls ( BOOL fHide, HWND Frame, HWND SysMenu, HWND TitleBar, HWND MinMax ) {
  2664.  
  2665.   /**************************************************************************
  2666.    * Get original window position and state.                                *
  2667.    **************************************************************************/
  2668.  
  2669.    SWP OldPosition ;
  2670.    WinQueryWindowPos ( Frame, &OldPosition ) ;
  2671.  
  2672.    BOOL WasVisible = WinIsWindowVisible ( Frame ) ;
  2673.  
  2674.   /**************************************************************************
  2675.    * Restore and hide the window.                                           *
  2676.    **************************************************************************/
  2677.  
  2678.    WinSetWindowPos ( Frame, 0, 0, 0, 0, 0, SWP_RESTORE | SWP_HIDE ) ;
  2679.  
  2680.   /**************************************************************************
  2681.    * Determine client window and location.                                  *
  2682.    **************************************************************************/
  2683.  
  2684.    SWP Position ;
  2685.    WinQueryWindowPos ( Frame, &Position ) ;
  2686.  
  2687.    RECTL Rectangle ;
  2688.    Rectangle.xLeft   = Position.x ;
  2689.    Rectangle.xRight  = Position.x + Position.cx ;
  2690.    Rectangle.yBottom = Position.y ;
  2691.    Rectangle.yTop    = Position.y + Position.cy ;
  2692.  
  2693.    WinCalcFrameRect ( Frame, &Rectangle, TRUE ) ;
  2694.  
  2695.   /**************************************************************************
  2696.    * Hide or reveal the controls windows by changing their parentage.       *
  2697.    **************************************************************************/
  2698.  
  2699.    if ( fHide ) {
  2700.       WinSetParent ( SysMenu,  HWND_OBJECT, FALSE ) ;
  2701.       WinSetParent ( TitleBar, HWND_OBJECT, FALSE ) ;
  2702.       WinSetParent ( MinMax,   HWND_OBJECT, FALSE ) ;
  2703.    } else {
  2704.       WinSetParent ( SysMenu,  Frame, TRUE ) ;
  2705.       WinSetParent ( TitleBar, Frame, TRUE ) ;
  2706.       WinSetParent ( MinMax,   Frame, TRUE ) ;
  2707.    } /* endif */
  2708.  
  2709.   /**************************************************************************
  2710.    * Tell the frame that things have changed.  Let it update the window.    *
  2711.    **************************************************************************/
  2712.  
  2713.    WinSendMsg ( Frame, WM_UPDATEFRAME,
  2714.       MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0 ) ;
  2715.  
  2716.   /**************************************************************************
  2717.    * Reposition the frame around the client window, which is left be.       *
  2718.    **************************************************************************/
  2719.  
  2720.    WinCalcFrameRect ( Frame, &Rectangle, FALSE ) ;
  2721.  
  2722.    #ifdef DEBUG
  2723.    Log ( "HideControls: Setting window position to %i,%i (%ix%i).",
  2724.       Rectangle.xLeft, Rectangle.yBottom,
  2725.       Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom ) ;
  2726.    #endif
  2727.  
  2728.    WinSetWindowPos ( Frame, 0,
  2729.      Rectangle.xLeft,  Rectangle.yBottom,
  2730.      Rectangle.xRight - Rectangle.xLeft,
  2731.      Rectangle.yTop - Rectangle.yBottom,
  2732.      SWP_SIZE | SWP_MOVE ) ;
  2733.  
  2734.   /**************************************************************************
  2735.    * If window was maximized, put it back that way.                         *
  2736.    **************************************************************************/
  2737.  
  2738.    if ( OldPosition.fl & SWP_MAXIMIZE ) {
  2739.       #ifdef DEBUG
  2740.       Log ( "HideControls: Maximizing window position to %i,%i (%ix%i).",
  2741.          Rectangle.xLeft, Rectangle.yBottom,
  2742.          Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom ) ;
  2743.       #endif
  2744.       WinSetWindowPos ( Frame, 0,
  2745.         Rectangle.xLeft,  Rectangle.yBottom,
  2746.         Rectangle.xRight-Rectangle.xLeft,
  2747.         Rectangle.yTop-Rectangle.yBottom,
  2748.         SWP_SIZE | SWP_MOVE | ( OldPosition.fl & SWP_MAXIMIZE ) ) ;
  2749.    } /* endif */
  2750.  
  2751.   /**************************************************************************
  2752.    * If the window was visible in the first place, show it.                 *
  2753.    **************************************************************************/
  2754.  
  2755.    if ( WasVisible )
  2756.       WinShowWindow ( Frame, TRUE ) ;
  2757. }
  2758.  
  2759. /****************************************************************************
  2760.  *                                                                          *
  2761.  *    Update Window                                                         *
  2762.  *                                                                          *
  2763.  ****************************************************************************/
  2764.  
  2765. STATIC void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All ) {
  2766.  
  2767.  /***************************************************************************
  2768.   * Determine how many items are to be displayed.                           *
  2769.   ***************************************************************************/
  2770.  
  2771.   int Count = 0 ;
  2772.   for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  2773.      Item *pItem = Data->IniData.Items[i].pItem ;
  2774.      if ( pItem->QueryFlag() ) {
  2775.         Count ++ ;
  2776.      } /* endif */
  2777.   } /* endfor */
  2778.  
  2779.  /***************************************************************************
  2780.   * Get presentation space and make it use RGB colors.                      *
  2781.   ***************************************************************************/
  2782.  
  2783.   HPS hPS = WinGetPS ( hwnd ) ;
  2784.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0, 0, 0 ) ;
  2785.   GpiSetCp ( hPS, Data->CodePage ) ;
  2786.  
  2787.  /***************************************************************************
  2788.   * Get the window's size and determine the initial position.               *
  2789.   ***************************************************************************/
  2790.  
  2791.   RECTL Rectangle ;
  2792.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2793.  
  2794.   Rectangle.xLeft += Data->Width / 2 ;
  2795.   Rectangle.xRight -= Data->Width / 2 ;
  2796.  
  2797.   Rectangle.yBottom = Data->Height * ( Count - 1 ) ;
  2798.   Rectangle.yTop = Rectangle.yBottom + Data->Height ;
  2799.  
  2800.  /***************************************************************************
  2801.   * Review all items.  Display those changed, or all.                       *
  2802.   ***************************************************************************/
  2803.  
  2804.   for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  2805.     Item *pItem = Data->IniData.Items[i].pItem ;
  2806.     if ( pItem->QueryFlag() ) {
  2807.       pItem->Repaint ( hPS, Rectangle, Data->IniData.TextColor, Data->IniData.BackColor, All ) ;
  2808.       Rectangle.yBottom -= Data->Height ;
  2809.       Rectangle.yTop    -= Data->Height ;
  2810.     } /* endif */
  2811.   } /* endfor */
  2812.  
  2813.  /***************************************************************************
  2814.   * Release the presentation space and return.                              *
  2815.   ***************************************************************************/
  2816.  
  2817.   WinReleasePS ( hPS ) ;
  2818. }
  2819.  
  2820.  
  2821. /****************************************************************************
  2822.  *                                                                          *
  2823.  *    Monitor Loop Thread                                                   *
  2824.  *                                                                          *
  2825.  ****************************************************************************/
  2826.  
  2827. STATIC VOID MonitorLoopThread ( PVOID Parameter ) {
  2828.  
  2829.   /**************************************************************************
  2830.    * Get the thread parameter.                                              *
  2831.    **************************************************************************/
  2832.  
  2833.    PMONITOR_PARMS Parms = PMONITOR_PARMS ( Parameter ) ;
  2834.  
  2835.   /**************************************************************************
  2836.    * Set this thread's priority.                                            *
  2837.    **************************************************************************/
  2838.  
  2839.    DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  2840.    DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MINIMUM+(*Parms->Priority), 0 ) ;
  2841.  
  2842.   /**************************************************************************
  2843.    * Start up the high resolution timer, if it is available.                *
  2844.    **************************************************************************/
  2845.  
  2846.    BOOL HiResTimer = OpenTimer ( ) ;
  2847.  
  2848.   /**************************************************************************
  2849.    * Loop while active . . .                                                *
  2850.    **************************************************************************/
  2851.  
  2852.    while ( Parms->Active ) {
  2853.  
  2854.      /***********************************************************************
  2855.       * Reset the last time and count seen.                                 *
  2856.       ***********************************************************************/
  2857.  
  2858.       ULONG LastMilliseconds ;
  2859.       TIMESTAMP Time [2] ;
  2860.  
  2861.       if ( HiResTimer )
  2862.          GetTime ( &Time[0] ) ;
  2863.       else
  2864.          DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &LastMilliseconds, sizeof(LastMilliseconds) ) ;
  2865.  
  2866.       ULONG LastCounter = *Parms->Counter ;
  2867.  
  2868.      /***********************************************************************
  2869.       * Let the counter count.                                              *
  2870.       ***********************************************************************/
  2871.  
  2872.       DosSleep ( *Parms->Interval ) ;
  2873.  
  2874.      /***********************************************************************
  2875.       * Find out how much time and counts went by.                          *
  2876.       ***********************************************************************/
  2877.  
  2878.       ULONG CurrentCounter = *Parms->Counter ;
  2879.  
  2880.       ULONG DeltaMilliseconds ;
  2881.  
  2882.       if ( HiResTimer ) {
  2883.          GetTime ( &Time[1] ) ;
  2884.  
  2885.          ULONG Nanoseconds ;
  2886.          DeltaMilliseconds = ComputeElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  2887.  
  2888.          if ( Nanoseconds >= 500000 )
  2889.             DeltaMilliseconds ++ ;
  2890.       } else {
  2891.          ULONG Milliseconds ;
  2892.          DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &Milliseconds, sizeof(Milliseconds) ) ;
  2893.          DeltaMilliseconds = Milliseconds - LastMilliseconds ;
  2894.       } /* endif */
  2895.  
  2896.      /***********************************************************************
  2897.       * Find out how much idle time was counted.  Adjust it to persecond.   *
  2898.       ***********************************************************************/
  2899.  
  2900.       ULONG Counter = (ULONG) ( ( (double)(CurrentCounter-LastCounter) * 1000 ) / (double)DeltaMilliseconds ) ;
  2901.  
  2902.      /***********************************************************************
  2903.       * Tell the owner window to refresh its statistics.                    *
  2904.       ***********************************************************************/
  2905.  
  2906.       WinPostMsg ( Parms->Owner, WM_REFRESH, MPFROMLONG(Counter), 0 ) ;
  2907.  
  2908.    } /* endwhile */
  2909.  
  2910.    MonitorThreadEvent.Post ( ) ;
  2911. }
  2912.  
  2913. /****************************************************************************
  2914.  *                                                                          *
  2915.  *      Update the Item List to reflect changes in the available drives.    *
  2916.  *                                                                          *
  2917.  ****************************************************************************/
  2918.  
  2919. STATIC VOID UpdateDriveList ( HAB Anchor, HMODULE Library, HINI IniHandle,
  2920.    PINIDATA IniData, Dde_Server *pDdeServer, ULONG OldDrives, ULONG NewDrives ) {
  2921.  
  2922.  /***************************************************************************
  2923.   * Get format strings.                                                     *
  2924.   ***************************************************************************/
  2925.  
  2926.   ResourceString LabelFormat ( Library, IDS_DRIVE_FREE ) ;
  2927.  
  2928.  /***************************************************************************
  2929.   * Save the old item list for comparison.                                  *
  2930.   ***************************************************************************/
  2931.  
  2932.   ITEM OldItems [ ITEM_BASE_COUNT + MAX_DRIVES ] ;
  2933.  
  2934.   memset ( OldItems, 0, sizeof(OldItems) ) ;
  2935.  
  2936.   USHORT OldCount = 0 ;
  2937.   if ( OldDrives ) {
  2938.      OldCount = USHORT ( IniData->ItemCount ) ;
  2939.      memcpy ( OldItems, IniData->Items, sizeof(OldItems) ) ;
  2940.   } /* endif */
  2941.  
  2942.  /***************************************************************************
  2943.   * Add items for each drive on the system.                                 *
  2944.   ***************************************************************************/
  2945.  
  2946.   USHORT Count = ITEM_BASE_COUNT ;
  2947.   USHORT OldIndex = ITEM_BASE_COUNT ;
  2948.  
  2949.   ULONG Drives = 0 ;
  2950.   NewDrives >>= 2 ;
  2951.   OldDrives >>= 2 ;
  2952.  
  2953.   for ( int Drive=3; Drive<=MAX_DRIVES; Drive++ ) {
  2954.  
  2955.      while ( ( OldIndex < OldCount )
  2956.         AND ( (SHORT)OldItems[OldIndex].pItem->QueryId() < ITEM_BASE_COUNT + Drive ) ) {
  2957.         OldIndex ++ ;
  2958.      } /* endwhile */
  2959.  
  2960.      if ( NewDrives & 1 ) {
  2961.         if ( OldDrives & 1 ) {
  2962.            Drives |= ( 1 << (Drive-1) ) ;
  2963.            if ( ( OldIndex < OldCount )
  2964.               AND ( (SHORT)OldItems[OldIndex].pItem->QueryId() == ITEM_BASE_COUNT + Drive ) ) {
  2965.               IniData->Items[Count++] = OldItems[OldIndex++] ;
  2966.            } /* endif */
  2967.         } else {
  2968.            BYTE FileSystem [80] = { 0 } ;
  2969.            BYTE DiskLabel [12] = { 0 } ;
  2970.            int DriveType = CheckDrive ( USHORT(Drive), FileSystem, DiskLabel ) ;
  2971.            if ( DriveType ) {
  2972.  
  2973.               if ( DriveType > 0 )
  2974.                  Drives |= ( 1 << (Drive-1) ) ;
  2975.  
  2976.               char Name [80] ;
  2977.               sprintf ( Name,   "ShowDrive%c:", Drive+'A'-1 ) ;
  2978.  
  2979.               char Label [80] ;
  2980.               sprintf ( Label,  PCHAR(LabelFormat),  Drive+'A'-1 ) ;
  2981.  
  2982.               IniData->Items[Count++].pItem = new DriveFree ( USHORT(ITEM_BASE_COUNT+Drive),
  2983.                  Name, Label, Label,  pDdeServer, "Items",
  2984.                  IniData->CountryInfo, IniData->ShowK,
  2985.                  USHORT(Drive), IniData->DriveError,
  2986.                  IniData->ShowFileSystemNames, FileSystem,
  2987.                  IniData->ShowDiskLabels, DiskLabel ) ;
  2988.            } /* endif */
  2989.         } /* endif */
  2990.  
  2991.      } else {
  2992.         if ( OldDrives & 1 ) {
  2993.            delete OldItems[OldIndex++].pItem ;
  2994.         } else {
  2995.            // Do nothing.
  2996.         } /* endif */
  2997.      } /* endif */
  2998.  
  2999.      NewDrives >>= 1 ;
  3000.      OldDrives >>= 1 ;
  3001.  
  3002.   } /* endfor */
  3003.  
  3004.  /***************************************************************************
  3005.   * Save the new item count.                                                *
  3006.   ***************************************************************************/
  3007.  
  3008.   IniData->ItemCount = Count ;
  3009.  
  3010.  /***************************************************************************
  3011.   * Fetch the display flags for the drives.                                 *
  3012.   ***************************************************************************/
  3013.  
  3014.   for ( int i=ITEM_BASE_COUNT; i<IniData->ItemCount; i++ ) {
  3015.  
  3016.      BOOL Flag = TRUE ;
  3017.      Item *pItem = IniData->Items[i].pItem ;
  3018.      ULONG Size ;
  3019.  
  3020.      if ( PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ(pItem->QueryName()), &Size )
  3021.         AND ( ( Size == sizeof(Flag) ) OR ( Size == sizeof(short) ) )
  3022.         AND PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ(pItem->QueryName()), &Flag, &Size ) ) {
  3023.  
  3024.      } /* endif */
  3025.  
  3026.      if ( Flag )
  3027.         pItem->SetFlag () ;
  3028.      else
  3029.         pItem->ResetFlag () ;
  3030.  
  3031.      char Tag [80] ;
  3032.      strcpy ( Tag, PCHAR(IniData->Items[i].pItem->QueryName()) ) ;
  3033.      strcat ( Tag, " Label" ) ;
  3034.      IniData->Items[i].fLabel = FALSE ;
  3035.      if ( PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ(Tag), &Size )
  3036.         AND ( Size == sizeof(IniData->Items[i].Label) )
  3037.         AND PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ(Tag), &IniData->Items[i].Label, &Size )
  3038.         AND IniData->Items[i].Label[0] ) {
  3039.  
  3040.         IniData->Items[i].fLabel = TRUE ;
  3041.         IniData->Items[i].pItem->SetLabel ( IniData->Items[i].Label ) ;
  3042.  
  3043.      } /* endif */
  3044.  
  3045.   } /* endfor */
  3046.  
  3047.  /***************************************************************************
  3048.   * Update the total free space object.                                     *
  3049.   ***************************************************************************/
  3050.  
  3051.   ( (TotalFree*) IniData->Items [ ITEM_TOTALFREE ] . pItem ) -> ResetMask ( Drives ) ;
  3052. }
  3053.  
  3054. /****************************************************************************
  3055.  *                                                                          *
  3056.  *      Check to see if drive should be added to display list.              *
  3057.  *                                                                          *
  3058.  ****************************************************************************/
  3059.  
  3060. STATIC int CheckDrive ( USHORT Drive, PBYTE FileSystem, PBYTE DiskLabel ) {
  3061.  
  3062.   /**************************************************************************
  3063.    * First, check to see if drive is local or remote.  Remote drives are    *
  3064.    *   always monitored.                                                    *
  3065.    **************************************************************************/
  3066.  
  3067.    BYTE Path [3] ;
  3068.    Path[0] = (BYTE) ( Drive + 'A' - 1 ) ;
  3069.    Path[1] = ':' ;
  3070.    Path[2] = 0 ;
  3071.  
  3072.    DosError ( FERR_DISABLEHARDERR ) ;
  3073.  
  3074.    BYTE Buffer [1024] ;
  3075.    ULONG Size = sizeof(Buffer) ;
  3076.    ULONG Status = DosQueryFSAttach ( Path, 0, FSAIL_QUERYNAME, (PFSQBUFFER2)Buffer, &Size ) ;
  3077.    DosError ( FERR_ENABLEHARDERR ) ;
  3078.  
  3079.    if ( Status ) {
  3080.       #ifdef DEBUG
  3081.       Log ( "ERROR: Unable to query drive %s for file system.  Status %04X.", Path, Status ) ;
  3082.       #endif
  3083.       return ( 0 ) ;   // Don't monitor.
  3084.    } /* endif */
  3085.  
  3086.    USHORT cbName = PFSQBUFFER2(Buffer)->cbName ;
  3087.    strcpy ( PCHAR(FileSystem), PCHAR(PFSQBUFFER2(Buffer+cbName)->szFSDName) ) ;
  3088.  
  3089.    if ( PFSQBUFFER2(Buffer)->iType == FSAT_REMOTEDRV ) {
  3090.       return ( -1 ) ;  // Monitor but don't include in the total over all drives.
  3091.    } /* endif */
  3092.  
  3093.   /**************************************************************************
  3094.    * Attempt to open the local drive as an entire device.  If unable to do  *
  3095.    *   so, we cannot monitor this drive.                                    *
  3096.    **************************************************************************/
  3097.  
  3098.    ULONG Action ;
  3099.    HFILE Handle ;
  3100.    Status = DosOpen ( Path, &Handle, &Action, 0, 0, FILE_OPEN,
  3101.       OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE |
  3102.       OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR, 0 ) ;
  3103.  
  3104.    if ( Status ) {
  3105.       #ifdef DEBUG
  3106.       Log ( "ERROR: Unable to open local drive %s.  Status %04X.", Path, Status ) ;
  3107.       #endif
  3108.       return ( 0 ) ;   // Don't monitor.
  3109.    } /* endif */
  3110.  
  3111.   /**************************************************************************
  3112.    * Check to see if the drive has removable media.  We cannot monitor such.*
  3113.    **************************************************************************/
  3114.  
  3115.    BOOL Addit = FALSE ;
  3116.    BYTE Command = 0 ;
  3117.    BYTE NonRemovable ;
  3118.  
  3119.    ULONG LengthIn = sizeof(Command) ;
  3120.    ULONG LengthOut = sizeof(NonRemovable);
  3121.  
  3122.    if ( NOT DosDevIOCtl ( Handle, 8, 0x20, &Command, sizeof(Command), &LengthIn,
  3123.       &NonRemovable, sizeof(NonRemovable), &LengthOut ) ) {
  3124.  
  3125.       Addit = NonRemovable ;
  3126.  
  3127.    } /* endif */
  3128.  
  3129.   /**************************************************************************
  3130.    * Close the drive.                                                       *
  3131.    **************************************************************************/
  3132.  
  3133.    DosClose ( Handle ) ;
  3134.  
  3135.   /**************************************************************************
  3136.    * Get the drive label.                                                   *
  3137.    **************************************************************************/
  3138.  
  3139.    FSINFO Info ;
  3140.    if ( DosQueryFSInfo ( Drive, FSIL_VOLSER, PBYTE(&Info), sizeof(Info) ) == 0 )
  3141.       strcpy ( PCHAR(DiskLabel), PCHAR(Info.vol.szVolLabel) ) ;
  3142.  
  3143.   /**************************************************************************
  3144.    * Return the final verdict.                                              *
  3145.    **************************************************************************/
  3146.  
  3147.    return ( int(Addit) ) ;    // Monitor and include in overall total if not removable.
  3148. }
  3149.  
  3150. /****************************************************************************
  3151.  *                                                                          *
  3152.  *                       Calibrate the Load Meter                           *
  3153.  *                                                                          *
  3154.  ****************************************************************************/
  3155.  
  3156. STATIC ULONG CalibrateLoadMeter ( PCOUNTER_PARMS Parms ) {
  3157.  
  3158.  /***************************************************************************
  3159.   * Set result to zero as a default.                                        *
  3160.   ***************************************************************************/
  3161.  
  3162.   double AdjustedMaxLoad = 0.0 ;
  3163.  
  3164.  /***************************************************************************
  3165.   * If HRTIMER.SYS has been installed . . .                                 *
  3166.   ***************************************************************************/
  3167.  
  3168.   if ( OpenTimer ( ) ) {
  3169.  
  3170.    /*************************************************************************
  3171.     * Increase this thread's priority to the maximum.                       *
  3172.     *************************************************************************/
  3173.  
  3174.     DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  3175.  
  3176.    /*************************************************************************
  3177.     * Create the calibration thread and set its priority next highest.      *
  3178.     *************************************************************************/
  3179.  
  3180.     CounterThreadEvent.Reset ( ) ;
  3181.     Parms->Active = TRUE ;
  3182.     TID tidCalibrate = StartThread ( "CounterThread", CounterThread, 0x3000, Parms ) ;
  3183.     DosSuspendThread ( tidCalibrate ) ;
  3184.     DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, tidCalibrate ) ;
  3185.     DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, -1, tidCalibrate ) ;
  3186.  
  3187.    /*************************************************************************
  3188.     * Reset the calibration count, get the time, and let the counter go.    *
  3189.     *************************************************************************/
  3190.  
  3191.     Parms->Counter = 0 ;
  3192.     TIMESTAMP Time[2] ;
  3193.     GetTime ( &Time[0] ) ;
  3194.     DosResumeThread ( tidCalibrate ) ;
  3195.  
  3196.    /*************************************************************************
  3197.     * Sleep for one second.                                                 *
  3198.     *************************************************************************/
  3199.  
  3200.     DosSleep ( 1000 ) ;
  3201.  
  3202.    /*************************************************************************
  3203.     * Suspend the calibration counter and get the time.                     *
  3204.     *************************************************************************/
  3205.  
  3206.     Parms->Active = FALSE ;
  3207.     CounterThreadEvent.Wait ( 10000 ) ;
  3208.     GetTime ( &Time[1] ) ;
  3209.  
  3210.    /*************************************************************************
  3211.     * Return priorities to normal.                                          *
  3212.     *************************************************************************/
  3213.  
  3214.     DosSetPriority ( PRTYS_THREAD, PRTYC_REGULAR, 0, 0 ) ;
  3215.  
  3216.    /*************************************************************************
  3217.     * Get the elapsed time and adjust the calibration count.                *
  3218.     *************************************************************************/
  3219.  
  3220.     ULONG Milliseconds ;
  3221.     ULONG Nanoseconds ;
  3222.     Milliseconds = ComputeElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  3223.  
  3224.     AdjustedMaxLoad = (double)Parms->Counter * 1.0E9 ;
  3225.     AdjustedMaxLoad /= (double)Milliseconds*1.0E6L + (double)Nanoseconds ;
  3226.  
  3227.    /*************************************************************************
  3228.     * Close down the connection to HRTIMER.SYS.                             *
  3229.     *************************************************************************/
  3230.  
  3231.     CloseTimer ( ) ;
  3232.   }
  3233.  
  3234.  /***************************************************************************
  3235.   * Return the adjusted calibration count.  If HRTIMER was not there, it    *
  3236.   *   will be zero.                                                         *
  3237.   ***************************************************************************/
  3238.  
  3239.   return ( (ULONG)AdjustedMaxLoad ) ;
  3240. }
  3241.  
  3242. /****************************************************************************
  3243.  *                                                                          *
  3244.  *                    General Purpose Counter Thread                        *
  3245.  *                                                                          *
  3246.  ****************************************************************************/
  3247.  
  3248. STATIC VOID CounterThread ( PVOID Parameter ) {
  3249.  
  3250.   /*************************************************************************
  3251.    * Count like mad.                                                       *
  3252.    *************************************************************************/
  3253.  
  3254.    PCOUNTER_PARMS Parms = PCOUNTER_PARMS ( Parameter ) ;
  3255.    while ( Parms->Active ) {
  3256.       Parms->Counter ++ ;
  3257.    } /* endwhile */
  3258.  
  3259.    CounterThreadEvent.Post ( ) ;
  3260. }
  3261.  
  3262.